U盘剪切到U盘的照片怎么打不开开,输了密码之后,上面显示已加载的安全盘过多,请关闭未使用的,再进行此操作,重新启动计算,

更多频道内容在这里查看
爱奇艺用户将能永久保存播放记录
过滤短视频
暂无长视频(电视剧、纪录片、动漫、综艺、电影)播放记录,
按住视频可进行拖动
&正在加载...
举报视频:
举报原因(必填):
请说明举报原因(300字以内):
请输入您的反馈
举报理由需要输入300字以内
感谢您的反馈~
请勿重复举报~
请刷新重试~
收藏成功,可进入
查看所有收藏列表
当前浏览器仅支持手动复制代码
视频地址:
flash地址:
html代码:
通用代码:
通用代码可同时支持电脑和移动设备的分享播放
用爱奇艺APP或微信扫一扫,在手机上继续观看
当前播放时间:
一键下载至手机
限爱奇艺安卓6.0以上版本
使用微信扫一扫,扫描左侧二维码,下载爱奇艺移动APP
其他安装方式:手机浏览器输入短链接http://71.am/udn
下载安装包到本机:
设备搜寻中...
请确保您要连接的设备(仅限安卓)登录了同一爱奇艺账号 且安装并开启不低于V6.0以上版本的爱奇艺客户端
连接失败!
请确保您要连接的设备(仅限安卓)登录了同一爱奇艺账号 且安装并开启不低于V6.0以上版本的爱奇艺客户端
部安卓(Android)设备,请点击进行选择
请您在手机端下载爱奇艺移动APP(仅支持安卓客户端)
使用微信扫一扫,下载爱奇艺移动APP
其他安装方式:手机浏览器输入短链接http://71.am/udn
下载安装包到本机:
爱奇艺云推送
请您在手机端登录爱奇艺移动APP(仅支持安卓客户端)
使用微信扫一扫,下载爱奇艺移动APP
180秒后更新
打开爱奇艺移动APP,点击“我的-扫一扫”,扫描左侧二维码进行登录
没有安装爱奇艺视频最新客户端?
简单粗暴一键破解附近的WiFi显示密码 这个神奇必须有
正在检测客户端...
您尚未安装客户端,正在为您下载...安装完成后点击按钮即可下载
30秒后自动关闭
简单粗暴一键破解附近的WiFi显示密码 这个神奇必须有">简单粗暴一键破解附近的WiFi显示密码 这个神奇必须有
请选择打赏金额:
播放量12.7万
播放量数据:快去看看谁在和你一起看视频吧~
更多数据:
热门短视频推荐
Copyright (C) 2018 & All Rights Reserved
您使用浏览器不支持直接复制的功能,建议您使用Ctrl+C或右键全选进行地址复制
正在为您下载爱奇艺客户端安装后即可快速下载海量视频
正在为您下载爱奇艺客户端安装后即可免费观看1080P视频
&li data-elem="tabtitle" data-seq="{{seq}}"& &a href="javascript:void(0);"& &span>{{start}}-{{end}}&/span& &/a& &/li&
&li data-downloadSelect-elem="item" data-downloadSelect-selected="false" data-downloadSelect-tvid="{{tvid}}"& &a href="javascript:void(0);"&{{pd}}&/a&
选择您要下载的《
后才可以领取积分哦~
每观看视频30分钟
+{{data.viewScore}}分
{{data.viewCount}}/3
{{if data.viewCount && data.viewCount != "0" && data.viewCount != "1" && data.viewCount != "2" }}
访问泡泡首页
+{{data.rewardScore}}分
{{if data.rewardCount && data.rewardCount != 0 && data.getRewardDayCount != 0}}1{{else}}0{{/if}}/1
{{if data.rewardCount && data.rewardCount != 0 && data.getRewardDayCount != 0}}
+{{data.signScore}}分
{{data.signCount}}/1
{{if data.signCount && data.signCount != 0}}
色情低俗内容
血腥暴力内容
广告或欺诈内容
侵犯了我的权力
还可以输入
您使用浏览器不支持直接复制的功能,建议您使用Ctrl+C或右键全选进行地址复制&一?  java概述 & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &&
&1.1  Java的不同版本:J2SE、J2EE、J2ME的区别 & & & & & & & & & & & & & & & & & & & & & & & &&
1998年12月,SUN公司发布了Java 1.2,开始使用&Java 2& 这一名称,目前我们已经很少使用1.2之前的版本,所以通常所说的Java都是指Java2。Java 有三个版本,分别为 J2SE、J2EE和J2ME,以下是详细介绍。
J2SE(Java 2 Platform Standard Edition) 标准版
J2SE是Java的标准版,主要用于开发客户端(桌面应用软件),例如常用的文本编辑器、下载软件、即时通讯工具等,都可以通过J2SE实现。J2SE包含了Java的核心类库,例如数据库连接、接口定义、输入/输出、网络编程等。学习Java编程就是从J2SE入手。
J2EE(Java 2 Platform Enterprise Edition) 企业版
J2EE是功能最丰富的一个版本,主要用于开发高访问量、大数据量、高并发量的网站,例如美团、去哪儿网的后台都是J2EE。通常所说的JSP开发就是J2EE的一部分。J2EE包含J2SE中的类,还包含用于开发企业级应用的类,例如EJB、servlet、JSP、XML、事务控制等。J2EE也可以用来开发技术比较庞杂的管理软件,例如ERP系统(Enterprise Resource Planning,企业资源计划系统)。
J2ME(Java 2 Platform Micro Edition) 微型版
J2ME 只包含J2SE中的一部分类,受平台影响比较大,主要用于嵌入式系统和移动平台的开发,例如呼机、智能卡、手机(功能机)、机顶盒等。在智能手机还没有进入公众视野的时候,你是否还记得你的摩托罗拉、诺基亚手机上有很多Java小游戏吗?这就是用J2ME开发的。Java的初衷就是做这一块的开发。注意:Android手机有自己的开发组件,不使用J2ME进行开发。Java5.0版本后,J2SE、J2EE、J2ME分别更名为Java SE、Java EE、Java ME,由于习惯的原因,我们依然称之为J2SE、J2EE、J2ME。
1.2  Java类库及其组织结构(Java API) & & & & & & & & & & & & & & & & & & & & & & & & & & &&
Java 官方为开发者提供了很多功能强大的类,这些类被分别放在各个包中,随JDK一起发布,称为Java类库或Java API。API(Application Programming Interface, 应用程序编程接口)是一个通用概念。例如我编写了一个类,可以获取计算机的各种硬件信息,它很强大很稳定,如果你的项目也需要这样一个功能,那么你就无需再自己编写代码,将我的类拿来直接用就可以。但是,我的类代码很复杂,让你读完这些代码不太现实,而且我也不希望你看到我的代码(你也没必要也不希望读懂这些晦涩的代码),我要保护我的版权,怎么办呢?我可以先将我的类编译,并附带一个文档,告诉你我的类怎么使用,有哪些方法和属性,你只需要按照文档的说明来调用就完全没问题,既节省了你阅读代码的时间,也保护了我的版权。例如,获取CPU信息的方法:& & getCpuInfo(int cpuType);这就是一个API。也就是说,该文档中描述的类的使用方法,就叫做API。我也可以开发一个软件,用来清理计算机中的垃圾文件,我比较有公益心,希望让更多的开发人员使用我的软件,我就会在发布软件的同时附带一个说明文档,告诉你怎样在自己的程序中调用,这也叫做API。Java API也有一个说明文档,入口地址:选择对应版本的Java,点击链接进入即可。J2SE 1.7 的API地址为:这个文档是在线的,官方会随时更新。当然你也可以下载到本地,请大家自己百度怎么下载。打开J2SE 1.7 的API文档,如下图所示:
图1 &API 文档
Java类库中有很多包:
以 java.* 开头的是Java的核心包,所有程序都会使用这些包中的类;
以 javax.* 开头的是扩展包,x 是&extension 的意思,也就是扩展。虽然 javax.* 是对 java.* 的优化和扩展,但是由于 javax.* 使用的越来越多,很多程序都依赖于 javax.*,所以 javax.* 也是核心的一部分了,也随JDK一起发布。
以 org.* 开头的是各个机构或组织发布的包,因为这些组织很有影响力,它们的代码质量很高,所以也将它们开发的部分常用的类随JDK一起发布。
在包的命名方面,为了防止重名,有一个惯例:大家都以自己域名的倒写形式作为开头来为自己开发的包命名,例如百度发布的包会以 com.baidu.* 开头,w3c组织发布的包会以 org.w3c.* 开头,微学苑发布的包会以 net.weixueyuan.* 开头&&组织机构的域名后缀一般为 org,公司的域名后缀一般为 com,可以认为 org.* 开头的包为非盈利组织机构发布的包,它们一般是开源的,可以免费使用在自己的产品中,不用考虑侵权问题,而以 com.* 开头的包往往由盈利性的公司发布,可能会有版权问题,使用时要注意。java中常用的几个包介绍:
该包提供了Java编程的基础类,例如 Object、Math、String、StringBuffer、System、Thread等,不使用该包就很难编写Java代码了。
该包提供了包含集合框架、遗留的集合类、事件模型、日期和时间实施、国际化和各种实用工具类(字符串标记生成器、随机数生成器和位数组)。
该包通过文件系统、数据流和序列化提供系统的输入与输出。
该包提供实现网络应用与开发的类。
该包提供了使用Java语言访问并处理存储在数据源(通常是一个关系型数据库)中的数据API。
这两个包提供了GUI设计与开发的类。java.awt包提供了创建界面和绘制图形图像的所有类,而javax.swing包提供了一组&轻量级&的组件,尽量让这些组件在所有平台上的工作方式相同。
javax.swing
提供了与自然语言无关的方式来处理文本、日期、数字和消息的类和接口。
更多的包和说明请参考API文档。
1.3  Java import以及Java类的搜索路径 & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &&
如果你希望使用Java包中的类,就必须先使用import语句导入。import语句与C语言中的 #include 有些类似,语法为:& & import package1[.package2&].package 为包名,classname 为类名。例如:☆☆☆
import java.util.D // 导入 java.util 包下的 Date 类
import java.util.S // 导入 java.util 包下的 Scanner 类
import javax.swing.*; // 导入 javax.swing 包下的所有类,* 表示所有类
import 只能导入包所包含的类,而不能导入包。
为方便起见,我们一般不导入单独的类,而是导入包下所有的类,例如 import java.util.*;。
Java 编译器默认为所有的 Java 程序导入了 JDK 的 java.lang 包中所有的类(import java.lang.*;),其中定义了一些常用类,如 System、String、Object、Math 等,因此我们可以直接使用这些类而不必显式导入。但是使用其他类必须先导入。前面讲到的&Hello World&程序使用了System.out.println(); 语句,System 类位于 java.lang 包,虽然我们没有显式导入这个包中的类,但是Java 编译器默认已经为我们导入了,否则程序会执行失败。
Java类的搜索路径
Java程序运行时要导入相应的类,也就是加载 .class 文件的过程。假设有如下的 import 语句:
import p1.T
该语句表明要导入 p1 包中的 Test 类。安装JDK时,我们已经设置了环境变量&CLASSPATH 来指明类库的路径,它的值为&.;%JAVA_HOME%\lib,而 JAVA_HOME 又为&D:\Program Files\jdk1.7.0_71,所以 CLASSPATH 等价于 .;D:\Program Files\jdk1.7.0_71\lib。Java 运行环境将依次到下面的路径寻找并载入字节码文件 Test.class:
.p1\Test.class("."表示当前路径)
D:\Program Files\jdk1.7.0_71\lib\p1\Test.class
如果在第一个路径下找到了所需的类文件,则停止搜索,否则继续搜索后面的路径,如果在所有的路径下都未能找到所需的类文件,则编译或运行出错。你可以在CLASSPATH变量中增加搜索路径,例如&.;%JAVA_HOME%\C:\javalib,那么你就可以将类文件放在 C:\javalib 目录下,Java运行环境一样会找到。
二?  java语法基础 & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &
2.1java数据类型以及变量的定义 & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &
Java 是一种强类型的语言,声明变量时必须指明数据类型。变量(variable)的值占据一定的内存空间。不同类型的变量占据不同的大小。Java中共有8种基本数据类型,包括4 种整型、2 种浮点型、1 种字符型、1 种布尔型,请见下表。
Java基本数据类型
数据类型说明所占内存举例备注
long最后要有一个L字母(大小写无所谓)。
单精度浮点型
1.2F,&223.56F
float最后要有一个F字母(大小写无所谓)。
双精度浮点型
1.2, 1.2D,&223.56,&223.56D
double最后最好有一个D字母(大小写无所谓)。
字符型数据只能是一个字符,由单引号包围。
true, false
对于整型数据,通常情况下使用 int 类型。但如果表示投放广岛长崎的原子弹释放出的能量,就需要使用 long 类型了。byte 和 short 类型主要用于特定的应用场合,例如,底层的文件处理或者需要控制占用存储空间量的大数组。在Java中,整型数据的长度与平台无关,这就解决了软件从一个平台移植到另一个平台时给程序员带来的诸多问题。与此相反,C/C++ 整型数据的长度是与平台相关的,程序员需要针对不同平台选择合适的整型,这就可能导致在64位系统上稳定运行的程序在32位系统上发生整型溢出。八进制有一个前缀 0,例如 010 对应十进制中的 8;十六进制有一个前缀 0x,例如 0xCAFE;从 Java 7 开始,可以使用前缀 0b 来表示二进制数据,例如 0b1001 对应十进制中的 9。同样从 Java 7 开始,可以使用下划线来分隔数字,类似英文数字写法,例如 1_000_000 表示 1,000,000,也就是一百万。下划线只是为了让代码更加易读,编译器会删除这些下划线。另外,不像 C/C++,Java 不支持无符号类型(unsigned)。float 类型有效数字最长为 7 位,有效数字长度包括了整数部分和小数部分。例如:
float x = 223.56F;
float y = 100.00f;
注意:每个float类型后面都有一个标志&F&或&f&,有这个标志就代表是float类型。double 类型有效数字最长为 15 位。与 float 类型一样,double 后面也带有标志&D&或&d&。例如:
double x = 23.45D;
double y = 422.22d;
double z = 562.234;
注意:不带任何标志的浮点型数据,系统默认是 double 类型。大多数情况下都是用 double 类型,float 的精度很难满足需求。不同数据类型应用举例:
public class Demo {
public static void main(String[] args){
char webName1 = '微';
char webName2 = '学';
char webName3 = '苑';
System.out.println("网站的名字是:" + webName1 + webName2 + webName3);
short x=22; // 十进制
int y=022; // 八进制
long z=0x22L; // 十六进制
System.out.println("转化成十进制:x = " + x + ", y = " + y + ", z = " + z);
//"+"前后字符串连接// 浮点型
float m = 22.45f;
double n = 10;
System.out.println("计算乘积:" + m + " * " + n + "=" + m*n);
运行结果:网站的名字是:微学苑转化成十进制:x = 22, y = 18, z = 34计算乘积:22.45 * 10.0=224.53从运行结果可以看出,即使浮点型数据只有整数没有小数,在控制台上输出时系统也会自动加上小数点,并且小数位全部置为 0。
对布尔型的说明
在C语言中,如果判断条件成立,会返回1,否则返回0,例如:
#include &stdio.h&
int main(){
int x = 100&10;
int y = 100&10;
printf("100&10 = %d\n", x);
printf("100&10 = %d\n", y);
运行结果:100&10 = 1100&10 = 0但是在Java中不一样,条件成立返回 true,否则返回 false,即布尔类型。例如:
public class Demo {
public static void main(String[] args){
boolean a = 100&10;
boolean b = 100&10;
System.out.println("100&10 = " + a);
System.out.println("100&10 = " + b);
System.out.println("100&10是对的");
System.out.println("100&10是错的");
运行结果:100&10 = true100&10 = false100&10是对的实际上,true 等同于1,false 等同于0,只不过换了个名称,并单独地成为一种数据类型。
2.2  Java数据类型转换(自动转换和强制转换) & & & & & & & & & & & & & & & & & & & & & & & & & & & &
数据类型的转换,分为自动转换和强制转换。自动转换是程序在执行过程中&悄然&进行的转换,不需要用户提前声明,一般是从位数低的类型向位数高的类型转换;强制类型转换则必须在代码中声明,转换顺序不受限制。
自动数据类型转换
自动转换按从低到高的顺序转换。不同类型数据间的优先关系如下:& & 低---------------------------------------------&高&&& byte,short,char-& int -& long -& float -& double运算中,不同类型的数据先转化为同一类型,然后进行运算,转换规则如下:
操作数1类型操作数2类型转换后的类型
byte、short、char
byte、short、char、int
byte、short、char、int、long
byte、short、char、int、long、float
强制数据类型转换
强制转换的格式是在需要转型的数据前加上&( )&,然后在括号内加入需要转化的数据类型。有的数据经过转型运算后,精度会丢失,而有的会更加精确,下面的例子可以说明这个问题。
public class Demo {
public static void main(String[] args){
x = (int)34.56 + (int)11.2; // 丢失精度
y = (double)x + (double)10 + 1; // 提高精度
System.out.println("x=" + x);
System.out.println("y=" + y);
运行结果:x=45y=56.0仔细分析上面程序段:由于在 34.56 前有一个 int 的强制类型转化,所以 34.56 就变成了 34。同样 11.2 就变成了 11 了,所以 x 的结果就是 45。在 x 前有一个 double 类型的强制转换,所以 x 的值变为 45.0,而 10 的前面也被强制成 double 类型,所以也变成 10.0,所以最后 y 的值变为 56。&
&2.3  Java数组的定义和使用 & & & & & & & & & & & & & & & & & & & & & & & & & & &
&如果希望保存一组有相同类型的数据,可以使用数组。
数组的定义和内存分配
Java 中定义数组的语法有两种:& & type arrayName[];&&& type[] arrayNtype 为Java中的任意数据类型,包括基本类型和组合类型,arrayName为数组名,必须是一个合法的标识符,[ ] 指明该变量是一个数组类型变量。例如:
int demoArray[];
int[] demoA
这两种形式没有区别,使用效果完全一样,读者可根据自己的编程习惯选择。与C、C++不同,Java在定义数组时并不为数组元素分配内存,因此[ ]中无需指定数组元素的个数,即数组长度。而且对于如上定义的一个数组是不能访问它的任何元素的,我们必须要为它分配内存空间,这时要用到运算符new,其格式如下:& & arrayName=new type[arraySize];其中,arraySize 为数组的长度,type 为数组的类型。如:
demoArray=new int[3];
为一个整型数组分配3个int 型整数所占据的内存空间。通常,你可以在定义的同时分配空间,语法为:& & type arrayName[] = new type[arraySize];例如:
int demoArray[] = new int[3];
数组的初始化
你可以在声明数组的同时进行初始化(静态初始化),也可以在声明以后进行初始化(动态初始化)。例如:
// 静态初始化
// 静态初始化的同时就为数组元素分配空间并赋值
int intArray[] = {1,2,3,4};
String stringArray[] = {"微学苑", "http://www.weixueyuan.net", "一切编程语言都是纸老虎"};
// 动态初始化
float floatArray[] = new float[3];
floatArray[0] = 1.0f;
floatArray[1] = 132.63f;
floatArray[2] = 100F;
可以通过下标来引用数组:& & arrayName[index];与C、C++不同,Java对数组元素要进行越界检查以保证安全性。每个数组都有一个length属性来指明它的长度,例如 intArray.length 指明数组 intArray 的长度。【示例】写一段代码,要求输入任意5个整数,输出它们的和。
import java.util.*;
public class Demo {
public static void main(String[] args){
int intArray[] = new int[5];
long total = 0;
int len = intArray.
// 给数组元素赋值
System.out.print("请输入" + len + "个整数,以空格为分隔:");
Scanner sc = new Scanner(System.in);
for(int i=0; i& i++){
intArray[i] = sc.nextInt();
// 计算数组元素的和
for(int i=0; i& i++){
total += intArray[i];
System.out.println("所有数组元素的和为:" + total);
运行结果:请输入5个整数,以空格为分隔:10 20 15 25 50所有数组元素的和为:120
数组的遍历
实际开发中,经常需要遍历数组以获取数组中的每一个元素。最容易想到的方法是for循环,例如:
int arrayDemo[] = {1, 2, 4, 7, 9, 192, 100};
for(int i=0,len=arrayDemo. i& i++){
System.out.println(arrayDemo[i] + ", ");
输出结果:1, 2, 4, 7, 9, 192, 100,不过,Java提供了&增强版&的for循环,专门用来遍历数组,语法为:
for( arrayType varName: arrayName ){
// Some Code
arrayType 为数组类型(也是数组元素的类型);varName 是用来保存当前元素的变量,每次循环它的值都会改变;arrayName 为数组名称。每循环一次,就会获取数组中下一个元素的值,保存到 varName 变量,直到数组结束。即,第一次循环 varName 的值为第0个元素,第二次循环为第1个元素......例如:
int arrayDemo[] = {1, 2, 4, 7, 9, 192, 100};
for(int x: arrayDemo){
System.out.println(x + ", ");
输出结果与上面相同。这种增强版的for循环也被称为&foreach循环&,它是普通for循环语句的特殊简化版。所有的foreach循环都可以被改写成for循环。但是,如果你希望使用数组的索引,那么增强版的 for 循环无法做到。
二维数组的声明、初始化和引用与一维数组相似:
int intArray[ ][ ] = { {1,2}, {2,3}, {4,5} };
int a[ ][ ] = new int[2][3];
//与c c++不同之处是定义的时候不占内存,需要重新分配空间
a[0][0] = 12;
a[0][1] = 34;
a[1][2] = 93;
Java语言中,由于把二维数组看作是数组的数组,数组空间不是连续分配的,所以不要求二维数组每一维的大小相同。例如:
int intArray[ ][ ] = { {1,2}, {2,3}, {3,4,5} };
int a[ ][ ] = new int[2][ ];
a[0] = new int[3];
a[1] = new int[5];
【示例】通过二维数组计算两个矩阵的乘积。
public class Demo {
public static void main(String[] args){
// 第一个矩阵(动态初始化一个二维数组)
int a[][] = new int[2][3];
// 第二个矩阵(静态初始化一个二维数组)
int b[][] = { {1,5,2,8}, {5,9,10,-3}, {2,7,-5,-18} };
// 结果矩阵
int c[][] = new int[2][4];
// 初始化第一个矩阵
for(int i=0; i&2; i++)
for(int j=0; j&3 ;j++)
a[i][j] = (i+1) * (j+2);
// 计算矩阵乘积
for (int i=0; i&2; i++){
for (int j=0; j&4; j++){
c[i][j]=0;
for(int k=0; k&3; k++)
c[i][j] += a[i][k] * b[k][j];
// 输出结算结果
for(int i=0; i&2; i++){
for (int j=0; j&4; j++)
System.out.printf("%-5d", c[i][j]);
System.out.println();
运行结果:25&& 65&& 14&& -65&50&& 130& 28&& -130几点说明:
上面讲的是静态数组。静态数组一旦被声明,它的容量就固定了,不容改变。所以在声明数组时,一定要考虑数组的最大容量,防止容量不够的现象。
如果想在运行程序时改变容量,就需要用到数组列表(ArrayList,也称动态数组)或向量(Vector)。
正是由于静态数组容量固定的缺点,实际开发中使用频率不高,被 ArrayList 或 Vector 代替,因为实际开发中经常需要向数组中添加或删除元素,而它的容量不好预估。
2.4  Java StringBuffer与StringBuider & & & & & & & & & & & & & & & & & & & & & & & & & & &&
String 的值是不可变的,每次对String的操作都会生成新的String对象,不仅效率低,而且耗费大量内存空间。StringBuffer类和String类一样,也用来表示字符串,但是StringBuffer的内部实现方式和String不同,在进行字符串处理时,不生成新的对象,在内存使用上要优于String。StringBuffer 默认分配16字节长度的缓冲区,当字符串超过该大小时,会自动增加缓冲区长度,而不是生成新的对象。StringBuffer不像String,只能通过 new 来创建对象,不支持简写方式,例如:
StringBuffer str1 = new StringBuffer(); // 分配16个字节长度的缓冲区
StringBuffer str2 = =new StringBuffer(512); // 分配512个字节长度的缓冲区
// 在缓冲区中存放了字符串,并在后面预留了16个字节长度的空缓冲区
StringBuffer str3 = new StringBuffer("www.weixueyuan.net");
StringBuffer类的主要方法
StringBuffer类中的方法主要偏重于对于字符串的操作,例如追加、插入和删除等,这个也是StringBuffer类和String类的主要区别。实际开发中,如果需要对一个字符串进行频繁的修改,建议使用 StringBuffer。
1) append() 方法
append() 方法用于向当前字符串的末尾追加内容,类似于字符串的连接。调用该方法以后,StringBuffer对象的内容也发生改变,例如:
StringBuffer str = new StringBuffer(&biancheng100&);
str.append(true);
则对象str的值将变成&biancheng100true&。注意是str指向的内容变了,不是str的指向变了。字符串的&+&操作实际上也是先创建一个StringBuffer对象,然后调用append()方法将字符串片段拼接起来,最后调用toString()方法转换为字符串。这样看来,String的连接操作就比StringBuffer多出了一些附加操作,效率上必然会打折扣。但是,对于长度较小的字符串,&+&操作更加直观,更具可读性,有些时候可以稍微牺牲一下效率。
2) &deleteCharAt()
deleteCharAt() 方法用来删除指定位置的字符,并将剩余的字符形成新的字符串。例如:
StringBuffer str = new StringBuffer("abcdef");
str. deleteCharAt(3);
该代码将会删除索引值为3的字符,即&d&字符。你也可以通过delete()方法一次性删除多个字符,例如:
StringBuffer str = new StringBuffer("abcdef");
str.delete(1, 4);
该代码会删除索引值为1~4之间的字符,包括索引值1,但不包括4。
3) insert() 方法
insert() 用来在指定位置插入字符串,可以认为是append()的升级版。例如:
StringBuffer str = new StringBuffer("abcdef");
str.insert(3, "xyz");
最后str所指向的字符串为 abcdxyzef。
4)&setCharAt() 方法
setCharAt() 方法用来修改指定位置的字符。例如:
StringBuffer str = new StringBuffer("abcdef");
str.setCharAt(3, 'z');
该代码将把索引值为3的字符修改为 z,最后str所指向的字符串为 abczef。以上仅仅是部分常用方法的简单说明,更多方法和解释请查阅API文档。
String和StringBuffer的效率对比
为了更加明显地看出它们的执行效率,下面的代码,将26个英文字母加了10000次。
public class Demo {
public static void main(String[] args){
String fragment = "abcdefghijklmnopqrstuvwxyz";
int times = 10000;
// 通过String对象
long timeStart1 = System.currentTimeMillis();
String str1 = "";
for (int i=0; i& i++) {
long timeEnd1 = System.currentTimeMillis();
System.out.println("String: " + (timeEnd1 - timeStart1) + "ms");
// 通过StringBuffer
long timeStart2 = System.currentTimeMillis();
StringBuffer str2 = new StringBuffer();
for (int i=0; i& i++) {
str2.append(fragment);
long timeEnd2 = System.currentTimeMillis();
System.out.println("StringBuffer: " + (timeEnd2 - timeStart2) + "ms");
运行结果:String: 5287msStringBuffer: 3ms结论很明显,StringBuffer的执行效率比String快上千倍,这个差异随着叠加次数的增加越来越明显,当叠加次数达到30000次的时候,运行结果为:String: 35923msStringBuffer: 8ms所以,强烈建议在涉及大量字符串操作时使用StringBuffer。
StringBuilder类
StringBuilder类和StringBuffer类功能基本相似,方法也差不多,主要区别在于StringBuffer类的方法是多线程安全的,而StringBuilder不是线程安全的,相比而言,StringBuilder类会略微快一点。StringBuffer、StringBuilder、String中都实现了CharSequence接口。CharSequence是一个定义字符串操作的接口,它只包括length()、charAt(int index)、subSequence(int start, int end) 这几个API。StringBuffer、StringBuilder、String对CharSequence接口的实现过程不一样,如下图所示:
图1 &对CharSequence接口的实现
可见,String直接实现了CharSequence接口;StringBuilder 和 StringBuffer都是可变的字符序列,它们都继承于AbstractStringBuilder,实现了CharSequence接口。
线程安全:
StringBuffer:线程安全
StringBuilder:线程不安全
速度:一般情况下,速度从快到慢为 StringBuilder & StringBuffer & String,当然这是相对的,不是绝对的。使用环境:
操作少量的数据使用 String;
单线程操作大量数据使用 StringBuilder;
多线程操作大量数据使用 StringBuffer。
&三?  java类和对象 & & & & & & & & & & & & & & & & & & & & & & & & & & & &
3.1  Java类的定义及其实例化 & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &
类必须先定义才能使用。类是创建对象的模板,创建对象也叫类的实例化。所谓的 实例化 说白了就是 创建对象实例化之后的对象 叫做实例下面通过一个简单的例子来理解Java中类的定义:
public class Dog{
void bark(){
System.out.println("汪汪,不要过来");
void hungry(){
System.out.println("主人,我饿了");
对示例的说明:
public 是类的修饰符,表明该类是公共类,可以被其他类访问。修饰符将在下节讲解。
class 是定义类的关键字。
Dog 是类名称。
name、age&是类的成员变量,也叫属性;bark()、hungry()&是类中的函数,也叫方法。
一个类可以包含以下类型变量:
局部变量:在方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。
成员变量:成员变量是定义在类中、方法体之外的变量。这种变量在创建对象的时候实例化(分配内存)。成员变量可以被类中的方法和特定类的语句访问。
类变量:类变量也声明在类中,方法体之外,但必须声明为static类型。static 也是修饰符的一种,将在下节讲解。
在类实例化的过程中自动执行的方法叫做构造方法,它不需要你手动调用。构造方法可以在类实例化的过程中做一些初始化的工作。构造方法的名称必须与类的名称相同,并且没有返回值。每个类都有构造方法。如果没有显式地为类定义构造方法,Java编译器将会为该类提供一个默认的构造方法。下面是一个构造方法示例:
public class Dog{
// 构造方法,没有返回值
Dog(String name1, int age1){
name = name1;
age = age1;
System.out.println("感谢主人领养了我");
// 普通方法,必须有返回值
void bark(){
System.out.println("汪汪,不要过来");
void hungry(){
System.out.println("主人,我饿了");
public static void main(String arg[]){
// 创建对象时传递的参数要与构造方法参数列表对应
Dog myDog = new Dog("花花", 3);
运行结果:感谢主人领养了我说明:
构造方法不能被显示调用。
构造方法不能有返回值,因为没有变量来接收返回值。
对象是类的一个实例,创建对象的过程也叫类的实例化。对象是以类为模板来创建的。在Java中,使用new关键字来创建对象,一般有以下三个步骤:
声明:声明一个对象,包括对象名称和对象类型。
实例化:使用关键字new来创建一个对象。
初始化:使用new创建对象时,会调用构造方法初始化对象。
Dog myD // 声明一个对象
myDog = new Dog("花花", 3); // 实例化
声明并没有分配空间,只有实例化后,才有了自己的空间
也可以在声明的同时进行初始化:
Dog myDog = new Dog("花花", 3);
访问成员变量和方法
通过已创建的对象来访问成员变量和成员方法,例如:
Dog myDog = new Dog("花花", 3);
// 通过点号访问成员变量
// 通过点号访问成员方法
myDog.bark();
下面的例子演示了如何访问成员变量和方法:
public class Dog{
Dog(String name1, int age1){
name = name1;
age = age1;
System.out.println("感谢主人领养了我");
void bark(){
System.out.println("汪汪,不要过来");
void hungry(){
System.out.println("主人,我饿了");
public static void main(String arg[]){
Dog myDog = new Dog("花花", 3);
// 访问成员变量
String name = myDog.
int age = myDog.
System.out.println("我是一只小狗,我名字叫" + name + ",我" + age + "岁了");
// 访问方法
myDog.bark();
myDog.hungry();
运行结果:感谢主人领养了我我是一只小狗,我名字叫花花,我3岁了汪汪,不要过来主人,我饿了
&3.2  Java访问修饰符(访问控制符) & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &&
&Java 通过修饰符来控制类、属性和方法的访问权限和其他功能,通常放在语句的最前端。例如:
public class className {
// body of class
private boolean myF
static final double weeks = 9.5;
protected static final int BOXWIDTH = 42;
public static void main(String[] arguments) {
// body of method
Java 的修饰符很多,分为访问修饰符和非访问修饰符。本节仅介绍访问修饰符,非访问修饰符会在后续介绍。访问修饰符也叫访问控制符,是指能够控制类、成员变量、方法的使用权限的关键字。在面向对象编程中,访问控制符是一个很重要的概念,可以使用它来保护对类、变量、方法和构造方法的访问。Java支持四种不同的访问权限:
修饰符说明
共有的,对所有类可见。
受保护的,对同一包内的类和所有子类可见。
私有的,在同一类内可见。
在同一包内可见。默认不使用任何修饰符。
public:公有的
被声明为public的类、方法、构造方法和接口能够被任何其他类访问。如果几个相互访问的public类分布在不用的包中,则需要导入相应public类所在的包。由于类的继承性,类所有的公有方法和变量都能被其子类继承。下面的方法使用了公有访问控制:
public static void main(String[] arguments) {
// body of method
Java程序的main() 方法必须设置成公有的,否则,Java解释器将不能运行该类。
protected:受保护的
被声明为protected的变量、方法和构造方法能被同一个包中的任何其他类访问,也能够被不同包中的子类访问。protected访问修饰符不能修饰类和接口,方法和成员变量能够声明为protected,但是接口的成员变量和成员方法不能声明为protected。子类能访问protected修饰符声明的方法和变量,这样就能保护不相关的类使用这些方法和变量。下面的父类使用了protected访问修饰符,子类重载了父类的bark()方法。
public class Dog{
protected void bark() {
System.out.println("汪汪,不要过来");
class Teddy extends Dog{
void bark() {
System.out.println("汪汪,我好怕,不要跟着我");
如果把bark()方法声明为private,那么除了Dog之外的类将不能访问该方法。如果把bark()声明为public,那么所有的类都能够访问该方法。如果我们只想让该方法对其所在类的子类可见,则将该方法声明为protected。&
private:私有的
私有访问修饰符是最严格的访问级别,所以被声明为private的方法、变量和构造方法只能被所属类访问,并且类和接口不能声明为private。声明为私有访问类型的变量只能通过类中公共的Getter/Setter方法被外部类访问。private访问修饰符的使用主要用来隐藏类的实现细节和保护类的数据。下面的类使用了私有访问修饰符:
public class Dog{
private int
public String getName() {
public void setName(String name) {
this.name =
public int getAge() {
public void setAge(int age) {
this.age =
例子中,Dog类中的name、age变量为私有变量,所以其他类不能直接得到和设置该变量的值。为了使其他类能够操作该变量,定义了两对public方法,getName()/setName() 和 getAge()/setAge(),它们用来获取和设置私有变量的值。this 是Java中的一个关键字,本章会讲到,你可以点击&&预览。在类中定义访问私有变量的方法,习惯上是这样命名的:在变量名称前面加&get&或&set&,并将变量的首字母大写。例如,获取私有变量 name 的方法为 getName(),设置 name 的方法为 setName()。这些方法经常使用,也有了特定的称呼,称为 Getter 和 Setter 方法。
默认的:不使用任何关键字
不使用任何修饰符声明的属性和方法,对同一个包内的类是可见的。接口里的变量都隐式声明为public static final,而接口里的方法默认情况下访问权限为public。如下例所示,类、变量和方法的定义没有使用任何修饰符:
class Dog{
void bark(){
System.out.println("汪汪,不要过来");
void hungry(){
System.out.println("主人,我饿了");
访问控制和继承
请注意以下方法继承(不了解继承概念的读者可以跳过这里,或者点击&&预览)的规则:
父类中声明为public的方法在子类中也必须为public。
父类中声明为protected的方法在子类中要么声明为protected,要么声明为public。不能声明为private。
父类中默认修饰符声明的方法,能够在子类中声明为private。
父类中声明为private的方法,不能够被继承。
如何使用访问控制符
访问控制符可以让我们很方便的控制代码的权限:
当需要让自己编写的类被所有的其他类访问时,就可以将类的访问控制符声明为 public。
当需要让自己的类只能被自己的包中的类访问时,就可以省略访问控制符。
当需要控制一个类中的成员数据时,可以将这个类中的成员数据访问控制符设置为 public、protected,或者省略。
&3.3  Java变量的作用域 & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &&
&在Java中,变量的作用域分为四个级别:类级、对象实例级、方法级、块级。类级变量又称全局级变量或静态变量,需要使用static关键字修饰,你可以与 C/C++ 中的 static 变量对比学习。类级变量在类定义后就已经存在,占用内存空间,可以通过类名来访问,不需要实例化。对象实例级变量就是成员变量,实例化后才会分配内存空间,才能访问。方法级变量就是在方法内部定义的变量,就是局部变量。块级变量就是定义在一个块内部的变量,变量的生存周期就是这个块,出了这个块就消失了,比如 if、for 语句的块。块是指由大括号包围的代码,例如:
int age = 3;
String name = "www.weixueyuan.net";
// 正确,在块内部可以访问 age 和 name 变量
System.out.println( name + "已经" + age + "岁了");
// 错误,在块外部无法访问 age 和 name 变量
System.out.println( name + "已经" + age + "岁了");
方法内部除了能访问方法级的变量,还可以访问类级和实例级的变量。
块内部能够访问类级、实例级变量,如果块被包含在方法内部,它还可以访问方法级的变量。
方法级和块级的变量必须被显示地初始化,否则不能访问。
演示代码:
public class Demo{
public static String name = "微学苑"; // 类级变量
public int // 对象实例级变量
// 属性块,在类初始化属性时候运行
int j = 2;// 块级变量
public void test1() {
int j = 3; // 方法级变量
if(j == 3) {
int k = 5; // 块级变量
// 这里不能访问块级变量,块级变量只能在块内部访问
System.out.println("name=" + name + ", i=" + i + ", j=" + j);
public static void main(String[] args) {
// 不创建对象,直接通过类名访问类级变量
System.out.println(Demo.name);
// 创建对象并访问它的方法
Demo t = new Demo();
t.test1();
运行结果:微学苑name=微学苑, i=0, j=3
&(this关键字和C++用法一样)
&(java方法重载和C++用法一样)
&3.4  Java类的基本运行顺序 & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &&
&我们以下面的类来说明一个基本的 Java 类的运行顺序:
public class Demo{
private int
public Demo(){
name = "微学苑";
public static void main(String[] args){
Demo obj = new Demo();
System.out.println(obj.name + "的年龄是" + obj.age);
基本运行顺序是:
先运行到第 9 行,这是程序的入口。
然后运行到第 10 行,这里要 new 一个Demo,就要调用 Demo 的构造方法。
就运行到第 5 行,注意:可能很多人觉得接下来就应该运行第 6 行了,错!初始化一个类,必须先初始化它的属性。
因此运行到第 2 行,然后是第 3 行。
属性初始化完过后,才回到构造方法,执行里面的代码,也就是第 6 行、第 7 行。
然后是第8行,表示 new 一个Demo实例完成。
然后回到 main 方法中执行第 11 行。
然后是第 12 行,main方法执行完毕。
作为程序员,应该清楚程序的基本运行过程,否则糊里糊涂的,不利于编写代码,也不利于技术上的发展。
&3.5  Java包装类、拆箱和装箱详解 & (类型转换) & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &
&虽然 Java 语言是典型的面向对象编程语言,但其中的八种基本数据类型并不支持面向对象编程,基本类型的数据不具备&对象&的特性&&不携带属性、没有方法可调用。 沿用它们只是为了迎合人类根深蒂固的习惯,并的确能简单、有效地进行常规数据处理。这种借助于非面向对象技术的做法有时也会带来不便,比如引用类型数据均继承了 Object 类的特性,要转换为 String 类型(经常有这种需要)时只要简单调用 Object 类中定义的toString()即可,而基本数据类型转换为 String 类型则要麻烦得多。为解决此类问题 ,Java为每种基本数据类型分别设计了对应的类,称之为包装类(Wrapper Classes),也有教材称为外覆类或数据类型类。
基本数据类型及对应的包装类
基本数据类型对应的包装类
以上是基本类型;
下面是C++和java中的一些概念
C++&   & java
类     & &类
对象    对象 & 或 实例 &(借用类占对象后的叫类)
类中函数   方法
      包&  (放功能相似的类的一个文件夹)
每个包装类的对象可以封装一个相应的基本类型的数据,并提供了其它一些有用的方法。包装类对象一经创建,其内容(所封装的基本类型数据值)不可改变。基本类型和对应的包装类可以相互装换:
装箱:int&Integer
拆箱:Integer&int
由基本类型向对应的包装类转换称为装箱,例如把 int 包装成 Integer 类的对象;
包装类向对应的基本类型转换称为拆箱,例如把 Integer 类的对象重新简化为 int。
包装类的应用
八个包装类的使用比较相似,下面是常见的应用场景。
1) 实现 int 和 Integer 的相互转换
可以通过 Integer 类的构造方法将 int 装箱,通过 Integer 类的 intValue 方法将 Integer 拆箱。例如:
public class Demo {
public static void main(String[] args) {
int m = 500;
Integer obj = new Integer(m); // 手动装箱
int n = obj.intValue(); // 手动拆箱
System.out.println("n = " + n);
Integer obj1 = new Integer(500);
System.out.println("obj 等价于 obj1?" + obj.equals(obj1));//拆箱
运行结果:n = 500obj 等价于 obj1?true
2) 将字符串转换为整数
Integer 类有一个静态的 paseInt() 方法,可以将字符串转换为整数,语法为:
parseInt(String s, int radix);
s 为要转换的字符串,radix 为进制,可选,默认为十进制。下面的代码将会告诉你什么样的字符串可以转换为整数:
public class Demo {
public static void main(String[] args) {
String str[] = {"123", "123abc", "abc123", "abcxyz"};
for(String str1 : str){                    //怎么理解
int m = Integer.parseInt(str1, 10);
System.out.println(str1 + " 可以转换为整数 " + m);
}catch(Exception e){
System.out.println(str1 + " 无法转换为整数");
运行结果:123 可以转换为整数 123123abc 无法转换为整数abc123 无法转换为整数abcxyz 无法转换为整数
3) 将整数转换为字符串
Integer 类有一个静态的 toString() 方法,可以将整数转换为字符串。例如:
public class Demo {
public static void main(String[] args) {
int m = 500;
String s = Integer.toString(m);
System.out.println("s = " + s);
运行结果:s = 500
自动拆箱和装箱
上面的例子都需要手动实例化一个包装类,称为手动拆箱装箱。Java 1.5(5.0) 之前必须手动拆箱装箱。Java 1.5 之后可以自动拆箱装箱,也就是在进行基本数据类型和对应的包装类转换时,系统将自动进行,这将大大方便程序员的代码书写。例如:
public class Demo {
public static void main(String[] args) {
int m = 500;
Integer obj = // 自动装箱
int n = // 自动拆箱
System.out.println("n = " + n);
Integer obj1 = 500;
System.out.println("obj 等价于 obj1?" + obj.equals(obj1));
//判断相等运算
运行结果:n = 500obj 等价于 obj1?true自动拆箱装箱是常用的一个功能,读者需要重点掌握。
&3.6&  再谈Java包 & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &
&在Java中,为了组织代码的方便,可以将功能相似的类放到一个文件夹内,这个文件夹,就叫做包。包不但可以包含类,还可以包含接口和其他的包。目录以"\"来表示层级关系,例如 E:\Java\workspace\Demo\bin\p1\p2\Test.java。包以"."来表示层级关系,例如 p1.p2.Test 表示的目录为 \p1\p2\Test.class。
如何实现包
通过 package 关键字可以声明一个包,例如:& & package p1.p2;必须将 package 语句放在所有语句的前面,例如:
package p1.p2;
public class Test {
public Test(){
System.out.println("我是Test类的构造方法");
表明 Test 类位于 p1.p2 包中。
在Java中,调用其他包中的类共有两种方式。
方法1) 在每个类名前面加上完整的包名
程序举例:
public class Demo {
public static void main(String[] args) {
java.util.Date today=new java.util.Date();
System.out.println(today);
运行结果:Wed Dec 03 11:20:13 CST 2014
方法2) 通过 import 语句引入包中的类
程序举例:
import java.util.D
// 也可以引入 java.util 包中的所有类
// import java.util.*;
public class Demo {
public static void main(String[] args) {
Date today=new Date();
System.out.println(today);
运行结果与上面相同。实际编程中,没有必要把要引入的类写的那么详细,可以直接引入特定包中所有的类,例如 import java.util.*;。
Java 在导入类时,必须要知道类的绝对路径。首先在&E:\Java\workspace\Demo\src\p0\ 目录(E:\Java\workspace\Demo\src\ 是项目源文件的根目录)下创建 Demo.java,输入如下代码:
package p0;
import p1.p2.T
public class Demo{
public static void main(String[] args){
Test obj = new Test();
再在&E:\Java\workspace\Demo\src\p1\p2 目录下创建 Test.java,输入如下代码:
package p1.p2;
public class Test {
public Test(){
System.out.println("我是Test类的构造方法");
假设我们将 classpath 环境变量设置为&.;D:\Program Files\jdk1.7.0_71\lib,源文件 Demo.java 开头有&import&p1.p2.T 语句,那么编译器会先检查 E:\Java\workspace\Demo\src\p0\p1\p2\ 目录下是否存在 Test.java 或 Test.class 文件,如果不存在,会继续检索&D:\Program Files\jdk1.7.0_71\lib\p1\p2\ 目录,两个目录下都不存在就会报错。显然,Test.java 位于&E:\Java\workspace\Demo\src\p1\p2\ 目录,编译器找不到,会报错,怎么办呢?可以通过 javac 命令的 classpath 选项来指定类路径。打开CMD,进入 Demo.java 文件所在目录,执行 javac 命令,并将 classpath 设置为&E:\Java\workspace\Demo\src,如下图所示:运行Java程序时,也需要知道类的绝对路径,除了 classpath 环境变量指定的路径,也可以通过 java 命令的 classpath 选项来增加路径,如下图所示:注意 java 命令与 javac 命令的区别,执行 javac 命令需要进入当前目录,而执行 java 命令需要进入当前目录的上级目录,并且类名前面要带上包名。可以这样来理解,javac是一个平台命令,它对具体的平台文件进行操作,要指明被编译的文件路径。而java是一个虚拟机命令,它对类操作,即对类的描述要用 点 分的描述形式,并且不能加扩展名,还要注意类名的大小写。这些命令比较繁杂,实际开发都需要借助 Eclipse,在Eclipse下管理包、编译运行程序都非常方便。Eclipse 实际上也是执行这些命令。
包的访问权限
被声明为 public 的类、方法或成员变量,可以被任何包下的任何类使用,而声明为 private 的类、方法或成员变量,只能被本类使用。没有任何修饰符的类、方法和成员变量,只能被本包中的所有类访问,在包以外任何类都无法访问它。
3.7  Java源文件的声明规则 & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &&
当在一个源文件中定义多个类,并且还有import语句和package语句时,要特别注意这些规则:
一个源文件中只能有一个public类。
一个源文件可以有多个非public类。
源文件的名称应该和public类的类名保持一致。例如:源文件中public类的类名是Employee,那么源文件应该命名为Employee.java。
如果一个类定义在某个包中,那么package语句应该在源文件的首行。
如果源文件包含import语句,那么应该放在package语句和类定义之间。如果没有package语句,那么import语句应该在源文件中最前面。
import语句和package语句对源文件中定义的所有类都有效。在同一源文件中,不能给不同的类不同的包声明。
类有若干种访问级别,并且类也分不同的类型:抽象类和final类等。这些将在后续章节介绍。
除了上面提到的几种类型,Java还有一些特殊的类,如内部类、匿名类。&
一个简单的例子
在该例子中,我们创建两个类 Employee 和 EmployeeTest,分别放在包 p1 和 p2 中。Employee类有四个成员变量,分别是 name、age、designation和salary。该类显式声明了一个构造方法,该方法只有一个参数。在Eclipse中,创建一个包,命名为 p1,在该包中创建一个类,命名为&Employee,将下面的代码复制到源文件中:
package p1;
public class Employee{
// Employee 类的构造方法
public Employee(String name){
this.name =
// 设置age的值
public void empAge(int empAge){
age = empA
// 设置designation的值
public void empDesignation(String empDesig){
designation = empD
// 设置salary的值
public void empSalary(double empSalary){
salary = empS
// 输出信息
public void printEmployee(){
System.out.println("Name:"+ name );
System.out.println("Age:" + age );
System.out.println("Designation:" + designation );
System.out.println("Salary:" + salary);
程序都是从main方法开始执行。为了能运行这个程序,必须包含main方法并且创建一个对象。下面给出EmployeeTest类,该类创建两个Employee对象,并调用方法设置变量的值。在Eclipse中再创建一个包,命名为 p2,在该包中创建一个类,命名为&EmployeeTest,将下面的代码复制到源文件中:
package p2;
import p1.*;
//这些是在EmployeeTest之外
public class EmployeeTest{
public static void main(String args[]){
// 创建两个对象
Employee empOne = new Employee("James Smith");
Employee empTwo = new Employee("Mary Anne");
// 调用这两个对象的成员方法
empOne.empAge(26);
empOne.empDesignation("Senior Software Engineer");
empOne.empSalary(1000);
empOne.printEmployee();
empTwo.empAge(21);
empTwo.empDesignation("Software Engineer");
empTwo.empSalary(500);
empTwo.printEmployee();
编译并运行&EmployeeTest 类,可以看到如下的输出结果:Name:James SmithAge:26Designation:Senior Software EngineerSalary:1000.0Name:Mary AnneAge:21Designation:Software EngineerSalary:500.0
&四?  java继承和多态 & & & & & & & & & & & & & & & & & & & & & & & & & &
4.1   java中继承的概念与实现 & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &
继承是类与类之间的关系,是一个很简单很直观的概念,与现实世界中的继承(例如儿子继承父亲财产)类似。继承可以理解为一个类从另一个类获取方法和属性的过程。如果类B继承于类A,那么B就拥有A的方法和属性。继承使用&extends 关键字。例如我们已经定义了一个类 People:
class People{
void say(){
System.out.println("我的名字是 " + name + ",年龄是 " + age + ",身高是 " + height);
如果现在需要定义一个类 Teacher,它也有 name、age、height 属性和 say() 方法,另外还需要增加 school、seniority、subject&属性和&lecturing() 方法,怎么办呢?我们要重新定义一个类吗?完全没必要,可以先继承 People 类的成员,再增加自己的成员即可,例如:
class Teacher extends People{         //在C++中
class teacher:public student
S // 所在学校
int // 教龄
// 覆盖 People 类中的 say() 方法
void say(){
System.out.println("我叫" + name + ",在" + school + "教" + subject + ",有" + seniority + "年教龄");
void lecturing(){
System.out.println("我已经" + age + "岁了,依然站在讲台上讲课");
对程序的说明
name 和 age 变量虽然没有在 Teacher 中定义,但是已在 People 中定义,可以直接拿来用。
Teacher 是 People 的子类,People 是Teacher 类的父类。
子类可以覆盖父类的方法。
子类可以继承父类除private以为的所有的成员。
构造方法不能被继承。
继承是在维护和可靠性方面的一个伟大进步。如果在 People 类中进行修改,那么 Teacher 类就会自动修改,而不需要程序员做任何工作,除了对它进行编译。单继承性:Java 允许一个类仅能继承一个其它类,即一个类只能有一个父类,这个限制被称做单继承性。后面将会学到接口(interface)的概念,接口允许多继承。(这一点是与C++不同的了,在C++中允许多继承,但没有接口interface这一说)最后对上面的代码进行整理:
public class Demo {
public static void main(String[] args) {
Teacher t = new Teacher();
t.name = "小布";
t.age = 70;
t.school = "清华大学";
t.subject = "Java";
t.seniority = 12;
t.lecturing();
class People{
void say(){
System.out.println("我的名字是 " + name + ",年龄是 " + age + ",身高是 " + height);
class Teacher extends People{
S // 所在学校
int // 教龄
// 覆盖 People 类中的 say() 方法
void say(){
System.out.println("我叫" + name + ",在" + school + "教" + subject + ",有" + seniority + "年教龄");
void lecturing(){
System.out.println("我已经" + age + "岁了,依然站在讲台上讲课");
运行结果:我叫小布,在清华大学教Java,有12年教龄我已经70岁了,依然站在讲台上讲课注意:构造方法不能被继承,掌握这一点很重要。 一个类能得到构造方法,只有两个办法:编写构造方法,或者根本没有构造方法,类有一个默认的构造方法。
4.2   java super 关键字 & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &&
super 关键字与&&类似,this 用来表示当前类的实例,super 用来表示父类。super 可以用在子类中,通过点号(.)来获取父类的成员变量和方法。super 也可以用在子类的子类中,Java 能自动向上层类追溯。父类行为被调用,就好象该行为是本类的行为一样,而且调用行为不必发生在父类中,它能自动向上层类追溯。super 关键字的功能:
调用父类中声明为 private 的变量(意味着public成员可以直接调用)。 在C++中 子类是严格不能调用父类中私有成员的!&
点取已经覆盖了的方法。
作为方法名表示父类构造方法。
调用隐藏变量和被覆盖的方法
public class Demo{
public static void main(String[] args) {
Dog obj = new Dog();
obj.move();
class Animal{
private String desc = "Animals are human's good friends";
// 必须要声明一个 getter 方法
public String getDesc() { return }
public void move(){
System.out.println("Animals can move");
class Dog extends Animal{
public void move(){
super.move(); // 调用父类的方法
System.out.println("Dogs can walk and run");
// 通过 getter 方法调用父类隐藏变量
System.out.println("Please remember: " + super.getDesc());
运行结果:Animals can moveDogs can walk and runPlease remember: Animals are human's good friendsmove() 方法也可以定义在某些祖先类中,比如父类的父类,Java 具有追溯性,会一直向上找,直到找到该方法为止。通过 super 调用父类的隐藏变量,必须要在父类中声明 getter 方法,因为声明为 private 的数据成员对子类是不可见的。
调用父类的构造方法
在许多情况下,使用默认构造方法来对父类对象进行初始化。当然也可以使用 super 来显示调用父类的构造方法。
public class Demo{
public static void main(String[] args) {
Dog obj = new Dog("花花", 3);
obj.say();
class Animal{
public Animal(String name){
this.name =
class Dog extends Animal{
public Dog(String name, int age){
super(name);
this.age =
public void say(){
System.out.println("我是一只可爱的小狗,我的名字叫" + name + ",我" + age + "岁了");
运行结果:我是一只可爱的小狗,我的名字叫花花,我3岁了
与C++比较:
public Dog(String name, int age){
super(name);
this.age =
Student::Student(char *name, int age, float score): People(name, age){ this-&score = }
注意:无论是 super() 还是 this(),都必须放在构造方法的第一行。值得注意的是:
在构造方法中调用另一个构造方法,调用动作必须置于最起始的位置。
不能在构造方法以外的任何方法内调用构造方法。
在一个构造方法内只能调用一个构造方法。
如果编写一个构造方法,既没有调用 super() 也没有调用 this(),编译器会自动插入一个调用到父类构造方法中,而且不带参数(和C++一样)。&最后注意 super 与 this 的区别:super 不是一个对象的引用,不能将 super 赋值给另一个对象变量,它只是一个指示编译器调用父类方法的特殊关键字。
4.3  Java继承中方法的覆盖和重载 & & & & & & & & & & & & & & & & & & & & & & & & &
在类继承中,子类可以修改从父类继承来的方法,也就是说子类能创建一个与父类方法有不同功能的方法,但具有相同的名称、返回值类型、参数列表。如果在新类中定义一个方法,其名称、返回值类型和参数列表正好与父类中的相同,那么,新方法被称做覆盖旧方法。参数列表又叫参数签名,包括参数的类型、参数的个数和参数的顺序,只要有一个不同就叫做参数列表不同。被覆盖的方法在子类中只能通过super调用。注意:覆盖不会删除父类中的方法,而是对子类的实例隐藏,暂时不使用。也就是说,当子类中有雨父类一模一样的方法(函数)时,父类中该函数虽然是public但在子类中却是隐藏的,要想调用父类中这个函数需要用super;请看下面的例子:
public class Demo{
public static void main(String[] args) {
Dog myDog = new Dog("花花");
myDog.say(); // 子类的实例调用子类中的方法
Animal myAnmial = new Animal("贝贝");
myAnmial.say(); // 父类的实例调用父类中的方法
class Animal{
public Animal(String name){
this.name =
public void say(){
System.out.println("我是一只小动物,我的名字叫" + name + ",我会发出叫声");
class Dog extends Animal{
// 构造方法不能被继承,通过super()调用
public Dog(String name){
super(name);
// 覆盖say() 方法
public void say(){
System.out.println("我是一只小狗,我的名字叫" + name + ",我会发出汪汪的叫声");
运行结果:我是一只小狗,我的名字叫花花,我会发出汪汪的叫声我是一只小动物,我的名字叫贝贝,我会发出叫声方法覆盖的原则:
覆盖方法的返回类型、方法名称、参数列表必须与原方法的相同。
覆盖方法不能比原方法访问性差(即访问权限不允许缩小)。
覆盖方法不能比原方法抛出更多的异常。
被覆盖的方法不能是final类型,因为final修饰的方法是无法覆盖的。
被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。
被覆盖的方法不能为static。如果父类中的方法为静态的,而子类中的方法不是静态的,但是两个方法除了这一点外其他都满足覆盖条件,那么会发生编译错误;反之亦然。即使父类和子类中的方法都是静态的,并且满足覆盖条件,但是仍然不会发生覆盖,因为静态方法是在编译的时候把静态方法和类的引用类型进行匹配。
方法的重载:前面已经对进行了说明,这里再强调一下,Java父类和子类中的方法都会参与重载,例如,父类中有一个方法是 func(){ ... },子类中有一个方法是 func(int i){ ... },就构成了方法的重载。覆盖和重载的不同:
方法覆盖要求参数列表必须一致,而方法重载要求参数列表必须不一致。
方法覆盖要求返回类型必须一致,方法重载对此没有要求。
方法覆盖只能用于子类覆盖父类的方法,方法重载用于同一个类中的所有方法(包括从父类中继承而来的方法)。
方法覆盖对方法的访问权限和抛出的异常有特殊的要求,而方法重载在这方面没有任何限制。
父类的一个方法只能被子类覆盖一次,而一个方法可以在所有的类中可以被重载多次。
4.4  Java多态和动态绑定 & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &
&在Java中,父类的变量可以引用父类的实例,也可以引用子类的实例。&请读者先看一段代码:
public class Demo {
public static void main(String[] args){
Animal obj = new Animal();
obj.cry();
obj = new Cat();
obj.cry();
obj = new Dog();
obj.cry();
class Animal{
// 动物的叫声
public void cry(){
System.out.println("不知道怎么叫");
class Cat extends Animal{
// 猫的叫声
public void cry(){
System.out.println("喵喵~");
class Dog extends Animal{
// 狗的叫声
public void cry(){
System.out.println("汪汪~");
运行结果:不知道怎么叫喵喵~汪汪~上面的代码,定义了三个类,分别是 Animal、Cat 和 Dog,Cat 和 Dog 类都继承自 Animal 类。obj 变量的类型为 Animal,它既可以指向 Animal 类的实例,也可以指向 Cat 和 Dog 类的实例,这是正确的。也就是说,父类的变量可以引用父类的实例,也可以引用子类的实例。注意反过来是错误的,因为所有的猫都是动物,但不是所有的动物都是猫。可以看出,obj 既可以是人类,也可以是猫、狗,它有不同的表现形式,这就被称为多态。多态是指一个事物有不同的表现形式或形态。再比如&人类&,也有很多不同的表达或实现,TA 可以是司机、教师、医生等,你憎恨自己的时候会说&下辈子重新做人&,那么你下辈子成为司机、教师、医生都可以,我们就说&人类&具备了多态性。多态存在的三个必要条件:要有继承、要有重写、父类变量引用子类对象。当使用多态方式调用方法时:
首先检查父类中是否有该方法,如果没有,则编译错误;如果有,则检查子类是否覆盖了该方法。
如果子类覆盖了该方法,就调用子类的方法,否则调用父类方法。
从上面的例子可以看出,多态的一个好处是:当子类比较多时,也不需要定义多个变量,可以只定义一个父类类型的变量来引用不同子类的实例。请再看下面的一个例子:
public class Demo {
public static void main(String[] args){
// 借助多态,主人可以给很多动物喂食
Master ma = new Master();
ma.feed(new Animal(), new Food());
ma.feed(new Cat(), new Fish());
ma.feed(new Dog(), new Bone());
// Animal类及其子类
class Animal{
public void eat(Food f){
System.out.println("我是一个小动物,正在吃" + f.getFood());
class Cat extends Animal{
public void eat(Food f){
System.out.println("我是一只小猫咪,正在吃" + f.getFood());
class Dog extends Animal{
public void eat(Food f){
System.out.println("我是一只狗狗,正在吃" + f.getFood());
// Food及其子类
class Food{
public String getFood(){
return "事物";
class Fish extends Food{
public String getFood(){
return "鱼";
class Bone extends Food{
public String getFood(){
return "骨头";
// Master类
class Master{
public void feed(Animal an, Food f){
an.eat(f);
运行结果:我是一个小动物,正在吃事物我是一只小猫咪,正在吃鱼我是一只狗狗,正在吃骨头Master 类的 feed 方法有两个参数,分别是 Animal 类型和 Food 类型,因为是父类,所以可以将子类的实例传递给它,这样 Master 类就不需要多个方法来给不同的动物喂食。
为了理解多态的本质,下面讲一下Java调用方法的详细流程。1) 编译器查看对象的声明类型和方法名。假设调用 obj.func(param),obj 为 Cat 类的对象。需要注意的是,有可能存在多个名字为func但参数签名不一样的方法。例如,可能存在方法 func(int) 和 func(String)。编译器将会一一列举所有 Cat 类中名为func的方法和其父类 Animal 中访问属性为 public 且名为func的方法。这样,编译器就获得了所有可能被调用的候选方法列表。2) 接下来,编泽器将检查调用方法时提供的参数签名。如果在所有名为func的方法中存在一个与提供的参数签名完全匹配的方法,那么就选择这个方法。这个过程被称为重载解析(overloading resolution)。例如,如果调用 func("hello"),编译器会选择 func(String),而不是 func(int)。由于自动类型转换的存在,例如 int 可以转换为 double,如果没有找到与调用方法参数签名相同的方法,就进行类型转换后再继续查找,如果最终没有匹配的类型或者有多个方法与之匹配,那么编译错误。这样,编译器就获得了需要调用的方法名字和参数签名。3) 如果方法的修饰符是private、static、final(static和final将在后续讲解),或者是构造方法,那么编译器将可以准确地知道应该调用哪个方法,我们将这种调用方式 称为静态绑定(static binding)。(说白了是编译器编译那些已经定好了)与此对应的是,调用的方法依赖于对象的实际类型, 并在运行时实现动态绑。例如调用 func("hello"),编泽器将采用动态绑定的方式生成一条调用 func(String) 的指令。(说白了就是编译的时候编译器有选择的进行编译)4)当程序运行,并且釆用动态绑定调用方法时,JVM一定会调用与 obj 所引用对象的实际类型最合适的那个类的方法。我们已经假设 obj 的实际类型是 Cat,它是 Animal 的子类,如果 Cat 中定义了 func(String),就调用它,否则将在 Animal 类及其父类中寻找。每次调用方法都要进行搜索,时间开销相当大,因此,JVM预先为每个类创建了一个方法表(method lable),其中列出了所有方法的名称、参数签名和所属的类。这样一来,在真正调用方法的时候,虚拟机仅查找这个表就行了。在上面的例子中,JVM 搜索 Cat 类的方法表,以便寻找与调用 func("hello") 相匹配的方法。这个方法既有可能是 Cat.func(String),也有可能是 Animal.func(String)。注意,如果调用super.func("hello"),编译器将对父类的方法表迸行搜索。假设 Animal 类包含cry()、getName()、getAge() 三个方法,那么它的方法表如下:cry() -& Animal.cry()getName() -& Animal.getName()getAge() -& Animal.getAge()实际上,Animal 也有默认的父类 Object(后续会讲解),会继承 Object 的方法,所以上面列举的方法并不完整。假设 Cat 类覆盖了 Animal 类中的 cry() 方法,并且新增了一个方法 climbTree(),那么它的参数列表为:cry() -& Cat.cry()getName() -& Animal.getName()getAge() -& Animal.getAge()climbTree() -& Cat.climbTree()在运行的时候,调用 obj.cry() 方法的过程如下:
JVM 首先访问 obj 的实际类型的方法表,可能是 Animal 类的方法表,也可能是 Cat 类及其子类的方法表。
JVM 在方法表中搜索与 cry() 匹配的方法,找到后,就知道它属于哪个类了。
JVM 调用该方法。
4.5  Java instanceof 运算符 & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &&
&多态性带来了一个问题,就是如何判断一个变量所实际引用的对象的类型 。 C++使用runtime-type information(RTTI),Java 使用 instanceof 操作符。instanceof 运算符用来判断一个变量所引用的对象的实际类型,注意是它引用的对象的类型,不是变量的类型。请看下面的代码:
public final class Demo{
public static void main(String[] args) {
// 引用 People 类的实例
People obj = new People();
if(obj instanceof Object){
System.out.println("我是一个对象");
if(obj instanceof People){
System.out.println("我是人类");
if(obj instanceof Teacher){
System.out.println("我是一名教师");
if(obj instanceof President){
System.out.println("我是校长");
System.out.println("-----------"); // 分界线
// 引用 Teacher 类的实例
obj = new Teacher();
if(obj instanceof Object){
System.out.println("我是一个对象");
if(obj instanceof People){
System.out.println("我是人类");
if(obj instanceof Teacher){
System.out.println("我是一名教师");
if(obj instanceof President){
System.out.println("我是校长");
class People{ }
class Teacher extends People{ }
class President extends Teacher{ }
运行结果:我是一个对象我是人类-----------我是一个对象我是人类我是一名教师
说白了是 & & 前者 &instanceof &后者;&前后两者嫡系 &前者大于等于后者 &前者是实例 后者是类可以看出,如果变量引用的是当前类或它的子类的实例,instanceof 返回 true,否则返回 false。
4.6  多态对象的类型转换 & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &&
&这里所说的对象类型转换,是指存在继承关系的对象,不是任意类型的对象。当对不存在继承关系的对象进行强制类型转换时,java 运行时将抛出 java.lang.ClassCastException 异常。在继承链中,我们将子类向父类转换称为&向上转型&,将父类向子类转换称为&向下转型&。很多时候,我们会将变量定义为父类的类型,却引用子类的对象,这个过程就是向上转型。程序运行时通过动态绑定来实现对子类方法的调用,也就是多态性。然而有些时候为了完成某些父类没有的功能,我们需要将向上转型后的子类对象再转成子类,调用子类的方法,这就是向下转型。注意:不能直接将父类的对象强制转换为子类类型,只能将向上转型后的子类对象再次转换为子类类型。也就是说,子类对象必须向上转型后,才能再向下转型。请看下面的代码:
public class Demo {
public static void main(String args[]) {
SuperClass superObj = new SuperClass();
SonClass sonObj = new SonClass();
// 下面的代码运行时会抛出异常,不能将父类对象直接转换为子类类型
// SonClass sonObj2 = (SonClass)superO
// 先向上转型,再向下转型
superObj = sonO
  //实际的效果是完成地址转移
SonClass sonObj1 = (SonClass)superO
class SuperClass{ }
class SonClass extends SuperClass{ }
将第7行的注释去掉,运行时会抛出异常,但是编译可以通过。因为向下转型存在风险,所以在接收到父类的一个引用时,请务必使用 instanceof 运算符来判断该对象是否是你所要的子类,请看下面的代码:
public class Demo {
public static void main(String args[]) {
SuperClass superObj = new SuperClass();
SonClass sonObj = new SonClass();
// superObj 不是 SonClass 类的实例
if(superObj instanceof SonClass){
SonClass sonObj1 = (SonClass)superO
System.out.println("①不能转换");
superObj = sonO
// superObj 是 SonClass 类的实例
if(superObj instanceof SonClass){
SonClass sonObj2 = (SonClass)superO
System.out.println("②不能转换");
class SuperClass{ }
class SonClass extends SuperClass{ }
运行结果:①不能转换总结:对象的类型转换在程序运行时检查,向上转型会自动进行,向下转型的对象必须是当前引用类型的子类。
4.7  Java static关键字以及Java静态变量和静态方法 & & & & & & & & & & & & & & & & & & & & & & & & & &
static 修饰符能够与变量、方法一起使用,表示是&静态&的。静态变量和静态方法能够通过类名来访问,不需要创建一个类的对象来访问该类的静态成员,所以static修饰的成员又称作类变量和类方法。静态变量与实例变量不同,实例变量总是通过对象来访问,因为它们的值在对象和对象之间有所不同。请看下面的例子:
public class Demo {
static int i = 10;
this.j = 20;
public static void main(String[] args) {
System.out.println("类变量 i=" + Demo.i);
Demo obj = new Demo();        //这样可以直接用
System.out.println("实例变量 j=" + obj.j);
运行结果:类变量 i=10实例变量 j=20
static 的内存分配
静态变量属于类,不属于任何独立的对象,所以无需创建类的实例就可以访问静态变量。之所以会产生这样的结果,是因为编译器只为整个类创建了一个静态变量的副本,也就是只分配一个内存空间,虽然有多个实例,但这些实例共享该内存。实例变量则不同,每创建一个对象,都会分配一次内存空间,不同变量的内存相互独立,互不影响,改变 a 对象的实例变量不会影响 b 对象。请看下面的代码:
public class Demo {
static int
//i只占一块固定的内存
public static void main(String[] args) {
Demo obj1 = new Demo();
obj1.i = 10;
obj1.j = 20;
Demo obj2 = new Demo();
System.out.println("obj1.i=" + obj1.i + ", obj1.j=" + obj1.j);
System.out.println("obj2.i=" + obj2.i + ", obj2.j=" + obj2.j);
运行结果:obj1.i=10, obj1.j=20obj2.i=10, obj2.j=0注意:静态变量虽然也可以通过对象来访问,但是不被提倡,编译器也会产生警告。上面的代码中,i 是静态变量,通过 obj1 改变 i 的值,会影响到 obj2;j 是实例变量,通过 obj1 改变 j 的值,不会影响到 obj2。这是因为 obj1.i 和 obj2.i 指向同一个内存空间,而 obj1.j 和 obj2.j 指向不同的内存空间,请看下图:
图1 &静态变量内存分配
注意:static 的变量是在类装载的时候就会被初始化。也就是说,只要类被装载,不管你是否使用了这个static 变量,它都会被初始化。小结:类变量(class variables)用关键字 static 修饰,在类加载的时候,分配类变量的内存,以后再生成类的实例对象时,将共享这块内存(类变量),任何一个对象对类变量的修改,都会影响其它对象。外部有两种访问方式:通过对象来访问或通过类名来访问。
静态方法是一种不能向对象实施操作的方法。例如,Math 类的 pow() 方法就是一个静态方法,语法为 Math.pow(x, a),用来计算 x 的 a 次幂,在使用时无需创建任何 Math 对象。因为静态方法不能操作对象,所以不能在静态方法中访问实例变量,只能访问自身类的静态变量。以下情形可以使用静态方法:
一个方法不需要访问对象状态,其所需参数都是通过显式参数提供(例如 Math.pow())。
一个方法只需要访问类的静态变量。
读者肯定注意到,main() 也是一个静态方法,不对任何对象进行操作。实际上,在程序启动时还没有任何对象,main() 方法是程序的入口,将被执行并创建程序所需的对象。关于静态变量和静态方法的总结:
一个类的静态方法只能访问静态变量;
一个类的静态方法不能够直接调用非静态方法;
如访问控制权限允许,静态变量和静态方法也可以通过对象来访问,但是不被推荐;
静态方法中不存在当前对象,因而不能使用&this,当然也不能使用&super;
静态方法不能被非静态方法覆盖;
构造方法不允许声明为 static 的;
局部变量不能使用static修饰。
静态方法举例:
public class Demo {
static int sum(int x, int y){
return x +
public static void main(String[] args) {//这里没有任何 &实例化&
下面是直接调用
int sum = Demo.sum(10, 10);
System.out.println("10+10=" + sum);
运行结果:10+10=20static 方法不需它所属的类的任何实例就会被调用,因此没有 this 值,不能访问实例变量,否则会引起编译错误。注意:实例变量只能通过对象来访问,不能通过类访问。
静态初始器(静态块)
块是由大括号包围的一段代码。静态初始器(Static Initializer)是一个存在于类中、方法外面的静态块。静态初始器仅仅在类装载的时候(第一次使用类的时候)执行一次,往往用来初始化静态变量。示例代码:
public class Demo {
public static int
System.out.println("Now in static block.");
public void test() {
System.out.println("test method: i=" + i);
public static void main(String[] args) {
System.out.println("Demo.i=" + Demo.i);
new Demo().test();
运行结果是:Now in static block.Demo.i=10test method: i=10
静态导入是 Java 5 的新增特性,用来导入类的静态变量和静态方法。一般我们导入类都这样写:
import packageName.classN // 导入某个特定的类
import packageName.*; // 导入包中的所有类
而静态导入可以这样写:
import static packageName.className.methonN // 导入某个特定的静态方法
import static packageName.className.*; // 导入类中的所有静态成员
导入后,可以在当前类中直接用方法名调用静态方法,不必再用 className.methodName 来访问。对于使用频繁的静态变量和静态方法,可以将其静态导入。静态导入的好处是可以简化一些操作,例如输出语句 System.out.println(); 中的 out 就是 System 类的静态变量,可以通过 import static java.lang.System.*; 将其导入,下次直接调用 out.println() 就可以了。请看下面的代码:
import static java.lang.System.*;
import static java.lang.Math.
public class Demo {
public static void main(String[] args) {
out.println("产生的一个随机数:" + random());
运行结果:产生的一个随机数:0.18705
&4.8  Java final关键字:阻止继承和多态 & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &
&在 Java 中,声明类、变量和方法时,可使用关键字 final 来修饰。final 所修饰的数据具有&终态&的特征,表示&最终的&意思。具体规定如下:
final 修饰的类不能被继承。
final 修饰的方法不能被子类重写。
final 修饰的变量(成员变量或局部变量)即成为常量,只能赋值一次。
final 修饰的成员变量必须在声明的同时赋值,如果在声明的时候没有赋值,那么只有 一次赋值的机会,而且只能在构造方法中显式赋值,然后才能使用。
final 修饰的局部变量可以只声明不赋值,然后再进行一次性的赋值。
final 一般用于修饰那些通用性的功能、实现方式或取值不能随意被改变的数据,以避免被误用,例如实现数学三角方法、幂运算等功能的方法,以及数学常量&=3.141593、e=2.71828 等。事实上,为确保终态性,提供了上述方法和常量的 java.lang.Math 类也已被定义为final 的。需要注意的是,如果将引用类型(任何类的类型)的变量标记为 final,那么该变量不能指向任何其它对象。但可以改变对象的内容,因为只有引用本身是 final 的。如果变量被标记为 final,其结果是使它成为常数。想改变 final 变量的值会导致一个编译错误。下面是一个正确定义 final 变量的例子:
public final int MAX_ARRAY_SIZE = 25; // 常量名一般大写
常量因为有 final 修饰,所以不能被继承。请看下面的代码:
public final class Demo{
public static final int TOTAL_NUMBER = 5;
public int
public Demo() {
// 非法,对final变量TOTAL_NUMBER进行二次赋值了
// 因为++TOTAL_NUMBER相当于 TOTAL_NUMBER=TOTAL_NUMBER+1
id = ++TOTAL_NUMBER;
public static void main(String[] args) {
final Demo t = new Demo();
final int i = 10;
j = 30; // 非法,对final变量进行二次赋值
final 也可以用来修饰类(放在 class 关键字前面),阻止该类再派生出子类,例如 Java.lang.String 就是一个 final 类。这样做是出于安全原因,因为要保证一旦有字符串的引用,就必须是类 String 的字符串,而不是某个其它类的字符串(String 类可能被恶意继承并篡改)。方法也可以被 final 修饰,被 final 修饰的方法不能被覆盖;变量也可以被 final 修饰,被 final 修饰的变量在创建对象以后就不允许改变它们的值了。一旦将一个类声明为 final,那么该类包含的方法也将被隐式地声明为 final,但是变量不是。被 final 修饰的方法为静态绑定,不会产生多态(动态绑定),程序在运行时不需要再检索方法表,能够提高代码的执行效率。在Java中,被 static 或 private 修饰的方法会被隐式的声明为 final,因为动态绑定没有意义。由于动态绑定会消耗资源并且很多时候没有必要,所以有一些程序员认为:除非有足够的理由使用多态性,否则应该将所有的方法都用 final 修饰。这样的认识未免有些偏激,因为 JVM 中的即时编译器能够实时监控程序的运行信息,可以准确的知道类之间的继承关系。如果一个方法没有被覆盖并且很短,编译器就能够对它进行优化处理,这个过程为称为内联(inlining)。例如,内联调用 e.getName() 将被替换为访问 e.name 变量。这是一项很有意义的改进,这是由于CPU在处理调用方法的指令时,使用的分支转移会扰乱预取指令的策略,所以,这被视为不受欢迎的。然而,如果 getName() 在另外一个类中被覆盖,那么编译器就无法知道覆盖的代码将会做什么操作,因此也就不能对它进行内联处理了。
4.9  java Object类 & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &
Object 类位于 java.lang 包中,是所有 Java 类的祖先,Java 中的每个类都由它扩展而来。定义Java类时如果没有显示的指明父类,那么就默认继承了 Object 类。例如:
public class Demo{
实际上是下面代码的简写形式:
public class Demo extends Object{
在Java中,只有基本类型不是对象,例如数值、字符和布尔型的值都不是对象,所有的数组类型,不管是对象数组还是基本类型数组都是继承自 Object 类。Object 类定义了一些有用的方法(如下),由于是根类,这些方法在其他类中都存在,一般是进行了重载或覆盖,实现了各自的具体功能。
equals() 方法
Object 类中的 equals() 方法用来检测一个对象是否等价于另外}

我要回帖

更多关于 u盘数据恢复后打不开 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信