Java复习手册
基础语法
概述
Java的特性
-
简单性
为了便于系统理解,Java语法在设计时尽可能地接近C++,但Java语法是C++语法的一个“纯净”版本,剔除了C++中许多很少使用、难以理解、容易混淆的特性。不过设计者没有试图清除C++中所有的特性,例如switch语句的语法在Java中就没有改变。
“简单”的另一方面是小,Java的目标之一是支持开发能够在小型机器上独立运行的软件。
-
面向对象
面向对象设计是一种程序设计技术,它将重点放在数据(即对象)和对象的接口上。用木匠打一个比方,“面向对象的”木匠始终首先关注的是所制作的椅子,其次才是所使用的工具;“非面向对象的”木匠主要 关注的是所用的工具。在本质上Java的面向对象能力和C++是一样的。
-
分布式
Java有一个丰富的例程库,用于处理像HTTP和FTP之类的TCP/IP协议。Java应用程序能够通过URL打开和访问网络上的对象,其便捷程度就好像访问本地文件一样。
-
健壮性
Java的设计目标之一在于使得Java编写的程序具有多方面的可靠性。Java特别强调进行早期的问题检查、后期动态的(运行时)检测,以及消除容易出错的情况。Java编译器能够检测许多在其它语言中仅在运行时才能检测出的问题,Java与C/C++最大的不同在于Java采用的指针模型可以消除重写内存和损坏数据的可能性。
-
安全性
Java要适用于网络/分布式环境,为了实现这个目标,安全性颇受重视。从一开始,Java就设计成能够防范各种攻击的语言,包括:运行时堆栈溢出,这是蠕虫和病毒的常用攻击手段;破坏自己的进程空间之外的内存;未经授权读写文件。
-
体系结构中立
编译器生成一个体系结构中立的目标文件格式,这是一种编译过的代码,只要有Java运行时系统,这些编译后的代码可以在许多处理器上运行。Java编译器通过生成与特定计算机体系结构无关的字节码指令来实现这一特性,精心设计的字节码不仅可以很容易地在任何机器上解释执行,而且还可以动态地转换成本地机器代码。
解释型虚拟机指令肯定比全速运行机器指令慢很多,但虚拟机有一个选项,可以将执行最频繁的字节码序列转换成机器码,这一过程称为即时编译。Java虚拟机还有一些其他优点,可以检查指令序列的行为,从而提高安全性。
-
可移植性
与C/C++不同,Java规范中没有“依赖具体实现”的地方,基本数据类型的大小以及有关运算的行为都有明确的说明。例如Java中的int永远是32位整数,而C/C++中可能是16位,32位,也可能是编译器开发商指定的其他任何大小。
在Java中,数值类型有固定的字节数,这消除了代码移植时一个主要问题,二进制数据以固定格式进行存储和传输,消除了字节顺序的困扰,字符串则采用标准的Unicode格式存储。
除了与用户界面有关的部分外,所有其他Java库确实能很好地支持平台独立性。你可以处理文件、正则表达式、XML、日期和时间、数据库、网络连接、线程等,而不用关心底层操作系统。不仅程序是可移植的,Java API往往也比原生API质量更高。
-
解释型
Java解释器可以在任何移植了解释器的机器上直接执行Java字节码,由于连接是一个增量式且轻量级的过程,所以开发过程也变得更加快捷,更加具有探索性。
-
高性能
尽管对解释后的字节码性能已较为满意,但在有些场合下还需要更高的性能。字节码可以(在运行时)动态地转换成对应运行这个应用地特定CPU的机器码。
现在的即时编译器已经非常出色,可以与传统编译器相媲美,在某些情况下甚至超越了传统编译器,原因是它们有更多的可用信息。例如即时编译器可以监控哪些代码频繁执行,并优化这些代码以提高速度。更为复杂的优化是消除函数调用(内联)。即时编译器知道哪些类已经加载,基于当前加载的类集合,如果一个特定函数不会被覆盖就可以使用内联,必要时还可以撤销这种优化。
-
多线程
多线程可以带来更快的交互响应和实时行为。在当时,Java是第一个支持并发程序设计的主流语言。
-
动态性
从很多方面看,Java相比C/C++更具有动态性,它能够适应不断发展的环境。库中可以自由地添加新方法和实例变量,而对客户端却没有任何影响。在Java中找出运行时类型信息十分简单。
Java发展史
版本 | 年份 | 新语言特性 |
---|---|---|
1.0 | 1996 | 语言本身 |
1.1 | 1997 | 内部类 |
1.2 | 1998 | strictfp修饰符 |
1.3 | 2000 | 无 |
1.4 | 2002 | 断言 |
5 | 2004 | 泛型类、for each循环、可变参数、自动装箱、元数据、枚举、静态导入 |
6 | 2006 | 无 |
7 | 2011 | 基于字符串的选择语句、菱形运算符、二进制字面量、异常增强处理 |
8 | 2014 | lambda表达式、包含默认方法的接口、流和日期/时间库 |
9 | 2017 | 模块、其他的语言和类库增强 |
基本程序设计结构
数据类型
Java是一种强类型语言,因此必须为每一个变量声明一种类型。在Java中一共有8种基本类型,其中有4种整形、2种浮点类型、1种字符类型char和1种用于表示真值的boolean类型。
-
整形
整形用于表示没有小数部分的数值,允许是负数,Java提供了4种整形。
类型 存储需求 取值范围 byte 1字节 -128~127 short 2字节 -32767~32767 int 4字节 -2147483648~2147483647(刚刚超过20亿) long 8字节 -9223372036854775808~9223372036854775807 int类型最常用,数量很大时需要使用long。byte和short类型主要用于特定场合,例如底层的文件处理或者存储空间很宝贵时的大数组。
在Java中,整形的范围与运行Java代码的机器无关,这就解决了软件从一个平台移植到另一个平台,或者在同一个平台的不同操作系统之间进行移植给程序员带来的诸多问题。与此相反,C/C++程序会针对不同处理器选择最为高效的整形,这样就会造成在32位处理器上运行的程序在16位系统上运行时却发生整数溢出。由于Java程序必须保证在所有机器上都得到相同的运行结果,所以各种数据类型的取值范围必须固定。
长整型数值有一个后缀L或者l,十六进制数有一个前缀0x或0X,八进制有一个前缀0,很显然八进制数容易混淆所以尽量不要使用八进制常数。
从Java7开始,加上前缀0b或0B就可以表示二进制数,还可以为数字字面量加下划线,例如1_000,这些下划线只是为了易读性,编译器会去除这些下划线。
-
浮点类型
浮点类型用于表示有小数部分的数值,Java中有2种浮点型。
类型 存储需求 取值范围 float 4字节 大约±3.40282347E+38F double 8字节 大约±1.79769313486231570E+308 double这种类型的精度是float的2倍,因此也称为双精度数值,很多情况下float类型的精度(6~7位有效数字)并不能满足需求,只有很少的情况下适合float,例如需要单精度的库或者需要存储大量数据时。
float类型的数值有一个后缀F或f,如果没有后缀的浮点数总认为是double类型,当然也可以在浮点数值后面添加后缀D或d。
常量Double.POSITIVE_INFINITY、DoubleNEGATIVE_INFINITY和Double.NaN分别表示正无穷大、负无穷大和NaN(不是一个数字)。
浮点数值不适用于无法接受舍入误差的金融计算,舍入误差的主要原因是浮点数值采用二进制系统表示,在二进制系统中无法精确地表示分数。如果在数值计算中不允许有任何舍入误差就应该使用BigDecimal类。
可移植性是Java语言的设计目标之一,无论在哪个虚拟机上执行,同一运算应该得到同样的结果。对于浮点数而言,实现这样的可移植性是十分困难的。Java虚拟机的最初规范要求所有中间计算必须进行截断,之后改进为默认情况下允许对中间计算采用扩展精度,但是对于使用了strictfp关键字标记的方法必须使用严格的浮点计算。
-
char类型
char类型(2字节)原本用于表示单个字符,不过现在情况有所变化,有些Unicode字符需要1个char值描述,有些Unicode字符需要2个char值描述。char类型的值可以表示为16进制值,范围从\u0000到\uFFFF。
一些特殊字符的转义序列:
转义序列 名称 Unicode值 \b 退格 \u0008 \t 制表 \u0009 \n 换号 \u000a \r 回车 \u000d \" 双引号 \u0022 \’ 单引号 \u0027 \\ 反斜杠 \u005c -
boolean类型
boolean类型(1字节)有两个值:false和true,用来判断逻辑条件。整型值和布尔值之间不能相互转换。
变量与常量
-
变量
变量名必须是一个以字母开头并由字母或数字构成的序列,与大多数语言相比,Java中的字母和数字的范围更大,字母包括’A’‘Z’,‘a’‘z’,’_’,’$‘或在某种语言中表示字母的任何Unicode字符。同样数字也包括’0’~'9’和在某种语言中表示数字的任何Unicode字符。不可使用空格,并且变量名是大小写敏感的,长度基本没有限制。
从Java10开始,对于局部变量,如果可以从变量的初始值推断出它的类型,就不再需要声明它的类型,只需要使用关键字var而无需指定类型。
-
常量
利用关键字final指示常量,final表示这个变量只能被赋值一次,一旦赋值之后就不能再更改了,习惯上变量名使用全大写。如果希望某个常量可以在一个类的多个方法使用,通常将这些常量称为类常量,使用关键字static final修饰。
运算符
-
算术运算符
当参与/运算的两个操作数都是整数时表示整数除法,否则表示浮点除法。整数被0除会产生一个异常,浮点数被0除会得到无穷大或NaN结果。
-
数学函数
计算平方根:
Math.sqrt(double a)
计算幂运算:
Math.pow(doube a,double b)
如果计算溢出,数学运算符只是返回一个错误结果而不做任何提醒,但如果是Math中的方法就会生成异常。
-
数值类型转换
无信息丢失的转换:byte->short、short->int、char->int、int->long、int->double、float->double
可能有精度损失的转换:int->float、long->float、long->double
当用二元运算符连接两个值时,先要将两个操作数转换为同一种类型再进行计算,如果两个操作数有一个是double类型,另一个操作数就转为double;否则如果有一个是float类型,另一个操作数就转为float;否则如果有一个操作数是long类型,另一个操作数就转为long;否则两个操作数都转为int。
-
强制类型转换
可能丢失信息的转换要通过强制类型转换完成,如果想对浮点数进行舍入运算,以便得到最接近的整数,可以使用Math.round(float/double a)方法。
-
结合赋值和运算符
可以在赋值时使用二元运算符,例如
x+=4
,等价于x=x+4
,如果运算符右边的值类型和左边不一致就会发生强制类型转换,例如x是int类型,x+=3.5
等价于x=(int)(x+3.5)
。 -
自增和自减运算符
自增和自减运算符改变的是变量的值,不能应用于数值本身,因此1++不是一个合法的语句。
后缀和前缀形式都会使变量值加1或减1,不同的是前缀形式会先完成运算,后缀形式会先使用变量原来的值。
-
关系和boolean运算符
Java沿用了C++的做法,使用&&表示逻辑“与”运算符,使用||表示逻辑"或"运算符,感叹号!就是逻辑非运算符。&&和||是按照"短路"方式来求值的,如果第一个操作数已经能够确定表达式的值,第二个操作数就不必计算了。
-
位运算符
位运算符包括
&
(与)、|
(或)、^
(异或)、~
(非)。>>
和<<
可以将位模式左移或右移,>>>
会用0填充高位,>>
会用符号位填充高位,不存在<<<
运算符。移位运算符的右操作数要完成模32的运算(除非左操作数是long类型,这种情况下需要模64),例如1<<35的值等于1<<3或者8。 -
括号与运算符级别
不使用括号就按照运算符优先级次序计算,同一级别的运算符按照从左到右的次序计算(右结合运算符除外)。
字符串
从概念上讲,Java字符串就是Unicode字符序列。Java没有内置的字符串类型,而是在标准Java类库中提供了一个与定义类,叫做String,每个用双引号引起来的字符串都是String类的一个实例。
-
子串
String类的substring方法可以从一个较大的字符串提取出一个字串。
substring方法的第一个参数是要复制的第一个位置,第二个参数是不想复制的第一个位置,例如substring(0,3)复制了0,1和2,不包括3。
substring的工作方式有一个优点:容易计算字串的长度,substring(a,b)的长度为b-a。
-
拼接
与绝大多数程序设计语言一样,Java语言允许使用+号连接(拼接)两个字符串。
当将一个字符串与一个非字符串的值拼接起来时,后者会转换成字符串(任何一个Java对象都可以转换成字符串)。例如
int age=13
,String rating="PG"+age
,将rating设置为"PG13"。如果需要把多个字符串放在一起,用一个界定符分隔,可以使用静态方法join,例如
String str=String.join("/","S","M","L")
将str设置为"S/M/L"。在Java11中,还提供了repeart方法,例如
String str="Java".repeat(3)
将str的值设为"JavaJavaJava"。 -
不可变字符串
String类没有提供修改字符串中某个字符的方法,由于不能修改Java字符串中的单个字符,所以Java文档中将String类对象称为不可变的,不过可以修改字符串变量,让它引用另一个字符串,就如同可以让原本存3的数值变量改成存放4一样。
通过拼接两个字符串来创建一个新字符串的效率确实不高,但是不可变字符串有一个优点:编译器可以让字符串共享。可以想象将各种字符串存放在公共的存储池中,字符串变量指向存储池中相应的位置,如果复制一个字符串变量,原始字符串与复制的字符串共享相同的字符。Java认为共享带来的高效率远胜于提取字串、拼接字符串所带来的低效率。
-
检查字符串是否相等
可以使用equals方法比较两个字符串的值是否相等,如果不区分大小写,可以使用equalsIgnoreCase方法。
运算符只能确定两个字符串是否存放在同一个位置上,如果虚拟机始终将相同的字符串共享,就可以使用运算符检测是否相等。但实际上只有字符串字面量是共享的,而+或substring等操作得到的字符串并不共享,不要使用==运算符测试字符串的相等性。
-
空串与Null串
空串""是长度为0的字符串,空串是一个Java对象,有自己的串长度(0)和内容(空),不过String变量还可以存放一个特殊的值,名为null,表示目前没有任何对象与该变量关联。
-
String类常用API
int compareTo(String other)
:按字典顺序比较,在other之前返回负数,之后返回正数,相等返回0。boolean equals(String other)
:比较两个字符串值是否相等。boolean startWith(String prefix)
:是否以prefix开头。boolean endsWith(String suffix)
:是否以suffix结尾。int indexOf(String str[,int fromIndex])
:返回与字符串str匹配的第一个子串的开始位置,从索引0或者fromIndex开始,不存在返回-1。int indexOf(int cp[,int fromIndex])
:返回与码点cp匹配的第一个子串的开始位置,从索引0或者fromIndex开始,不存在返回-1。int length()
:返回字符串代码单元的长度。String replace(CharSequence old,CharSequence new)
:返回新字符串,用new代替所有的old。String substring(int begin[,int end])
:返回新字符串,包含原始字符串从begin到末尾或end-1的所有代码单元。String trim()
:返回一个新字符串,删除原始字符串头部和尾部小于等于U+0020的字符。 -
构建字符串
有时候需要由较短的字符串构建字符串,如果采用字符串拼接的方式来达到目的,效率会比较低。每次拼接字符串时都会构建一个新的String对象,既耗时又浪费空间。可以使用StringBuilder来解决该问题。
StringBuilder在Java5中引入,这个类的前身是StringBuffer,它的效率低但是线程安全。如果所有字符串编辑操作都在单个线程中执行(通常都是这样),则应该使用StringBuilder。
输入与输出
-
读取输入
读取标准输入流首先需要构造一个与标准输入流关联的Scanner对象,
nextLine()
方法将读取一整行输入;如果想要读取一个单词(以空白符作为分隔符),可以使用next()
方法;如果想要读取一个整数,可以使用nextInt()
方法;如果想要读取下一个浮点数就是要nextDouble()
方法;hasNext()
可以检测输入中是否还有其他单词,hashNextInt()
和hashNextDouble()
检测是否还有下一个表示整数或浮点数的字符序列。 -
格式化输出
可以使用printf方法实现格式化输出,例如x的值为10000.0/3.0调用printf("%8.2f",x)将输出
3333.33
,8代表输出的字符宽度,精度是小数点后2个字符,由于3333.33只有7个字符宽,所以还会打印一个前导的空格。每一个以%后面的转换符都说明了要格式化的数值类型,除了f表示浮点数,还有s表示字符串,d表示十进制整数,c表示字符,b表示布尔等。除了printf也可以用静态方法
String.format
创建一个格式化的字符串。
控制流程
与任何程序设计语言一样,Java使用条件语句和循环结构确定控制流程。
-
块作用域
块(即复合语句)是指由若干条Java语句组成的语句,并用一对大括号括起来。块确定了变量的作用域,一个块可以嵌套在另一个块中。不能在嵌套的两个块中声明同名的变量。
-
条件语句
if中的条件为true时会执行对应语句,else是可选的,总是与最近的if构成一组。
-
for循环
for循环语句是支持迭代的一种通用结构,由一个计数器或类似的变量控制迭代次数,每次迭代后这个变量将会更新。for语句的第1部分通常是对计数器初始化,第2部分给出每次新一轮循环执行前要检测的循环条件,第3部分指定如何更新计数器。
for语句内部定义的变量,不能在循环体之外使用。因此如果希望在for循环体之外使用循环计数器的最终值,就要确保这个变量在循环之外声明。
-
while循环
while语句在最前面检测循环条件,因此循环体中的代码有可能一次都不执行。如果希望循环体至少执行一次可以使用do-while循环,这种循环语句先执行语句再检测循环条件。
-
多重选择:switch语句
在处理多个选项时,使用if/else会显得有些笨拙,Java有一个和C/C++完全相同的switch语句。switch语句将从选项值相匹配的case标签开始执行,直到遇到break语句,或者执行到switch语句的结束处为止。如果没有匹配的case语句而有default语句就执行这个default子句。
case标签可以是char、byte、short、或int的常量表达式,枚举常量,从Java7开始,还可以支持字符串字面量。当使用枚举常量时,不必在每个标签中指明枚举名,可以由switch的表达式值推导得出。
-
中断控制流程的语句
不带标签的break语句,和用于退出swicth语句的break语句一样,可以用于直接退出循环。
还可以使用带标签的break语句,可以用于跳出多重循环的嵌套语句。标签必须放在最外层循环之前,并且紧跟一个冒号。
continue语句将中断正常的控制流程,将控制转移到最内层循环的首部,如果continue用于for循环,就可以跳到for循环的更新部分,还有一种带标签的continue,将跳到与标签匹配的循环的首部。
大数
如果基本的整数和浮点数精度不能够满足需求,那么可以使用java.math包中的两个很有用的类:BigInteger和BigDecimal,这两个类可以处理包含任意长度数字序列的数值。BigInteger类实现任意精度的整数运算,BigDecimal类实现任意精度的浮点数运算。
使用静态的valueOf
方法可以将普通的数值转换为大数,对于更大的数,可以使用一个带字符串参数的构造器。不能使用算术运算符处理大数,例如+和*,而需要大数类的add和multiply方法。除此之外的其他方法:substract求差,divide求商,mod求余,sqrt求平方根,compareTo比较两个数。
数组
-
声明
数组是一种数据结构,用来存储同一类型值的集合。通过一个整形下标(index,或称索引)可以访问数组中的每一个值。在声明数组变量时,需要指出数组类型和数组变量的名字。
一旦创建了数组就不能再改变它的长度,如果程序运行中需要经常扩展数组的大小,就应该使用另一种数据结构:数组列表ArrayList。
-
访问元素
创建一个数字数组时,所有元素都初始化为0,boolean数组的元素会初始化为false,对象数组的元素则初始化为一个特殊值null,表示这些元素还未存放任何对象。
Java可以使用增强for循环来依次处理数组(或者其他元素集合)中的每一个元素,而不必考虑指定下标值。可以使用的必须是一个数组或者一个实现了Iterable接口的类对象。如果想打印数组中的所有值可以调用静态的
Arrays.toString
方法。 -
数组拷贝
如果希望将一个数组的所有值拷贝到一个新的数组中去,可以使用
Arrays.copyOf(int[] arr,int len)
方法,第2个参数是新数组的长度,这个方法通常用于增加数组的大小,如果数组元素是数值型那么额外的元素将被赋值0,如果数组元素是布尔型则赋值false。相反如果长度小于原始数组的长度,则只拷贝前面的值。这个方法实际上调用了System.arraycopy
方法,效率一般。使用
System.arraycopy(Object src,int srcPos,Object dest,int destPos,int length)
拷贝数组,前2个参数是原数组和拷贝位置,之后2个参数是目标数组和拷贝位置,最后一个参数代表拷贝长度,这是一个本地方法,效率最高,尤其在数组很大时尤为明显。也可以使用for循环和clone方法拷贝数组,for循环适合于小数组的拷贝,数组越大效率越低。 -
数组排序
可以使用Arrays类中的sort方法,这个方法使用了优化的快速排序,快速排序算法对于大多数数据集合来说都是效率比较高的。
面向对象
概述
面向对象程序涉设计(OOP)是当今主流的程序设计泛型,面向对象的程序是由对象组成的,每个对象包含对用户公开的特定部分和隐藏的实现部分。传统的结构化程序通过设计一系列算法求解问题,首先考虑的是如何操作数据,然后再考虑组织数据的结构,而面向对象中数据是第一位的,然后再考虑操作数据的算法。对于规模较小的问题,面向过程开发比较理性,面向对象更加适合解决规模较大的问题。
类
类是构造对象的模板或蓝图,由类构造对象的过程称为创建类的实例。
封装是处理对象的一个重要概念,从形式上看封装就是将数据和行为组合在一个包中,并对对象的使用者隐藏具体的实现方式。对象中的数据称为实例字段,操作数据的过程称为方法。作为一个类的实例,特定对象都有一组特定的实例字段值,这些值的集合就是这个对象的当前状态。
封装给予了对象黑盒特征,这是提高重用性和可靠性的关键。这意味着一个类完全可以改变数据存储的方式,只要仍使用同样的方法操作数据,其他对象就不会知道也不用关心这个类的变化。
类之间的关系:
- 依赖,即uses-a关系,如果一个类的方法使用或操纵另一个类的对象,我们就说一个类依赖于另一个类。
- 聚合,即has-a关系,即一个对象包含另一个对象。
- 继承,即is-a关系,表示一个更特殊的类与一个更一般的类之间的关系。
构造器
Java语言中要使用构造器用来构造新实例,构造器是一种特殊的方法,用来构造并初始化对象。
构造器的名字与类名相同,想要构造一个新实例需要在构造器前加上new操作符。在Java中,任何对象变量的值都是对存储在另一个地方的某个对象的引用,new操作符返回值也是一个引用。
每个类可以有一个以上的构造器,构造器可以0或多个参数,构造器没有返回值,构造器总是伴随new操作符一起使用。
静态字段和方法
如果将一个字段定义为static,每个类只有一个这样的字段,而对于非静态的实例字段,每个对象都有自己的一个副本。
静态方法是用static修饰的方法,静态方法不在对象上指向,可以认为静态方法是没有this参数的方法(在一个非静态方法中,this参数指示这个方法的隐式参数)。可以使用对象调用静态方法,但容易造成混淆,建议使用类名调用。
可以使用静态方法的情况:
- 方法不需要方法对象的状态,因为它所需要的所有参数都通过显示参数提供。
- 方法只需要访问类的静态字段。
静态方法还有一种常见用途,就是使用静态工厂方法来构造对象。
方法参数
按值调用表示方法接收的是调用者提供的值,按引用调用表示方法接收的是调用者提供的变量地址。方法可以修改按引用传递的变量的值,而不能修改按值传递的变量的值。Java中总是采用按值调用,也就是说方法得到的是所有参数值的一个副本,方法不能修改传递给它的任何参数变量的内容,实际上对象引用是按值传递的。
对象构造
-
重载
如果多个方法具有相同的名字、不同的参数,便出现了重载。如果编译器找不到匹配的参数就会产生编译时错误,查找匹配的过程叫做重载解析。
Java允许重载任何方法,要完整描述一个方法需要指定方法名和参数类型,这叫做方法的签名。返回类型不是方法签名的一部分,因此不能有两个名字相同、参数类型也相同却有不同返回类型的方法。
-
默认字段初始化
如果在构造器中没有显示地为字段设置初值,那么就会被自动赋为默认值:数值为0、布尔值为false、对象引用为null。
方法中的局部变量必须明确地初始化,不能不设置初始值。
-
无参构造器
很多类都包含无参构造器,由无参构造器创建对象时,对象的状态会设置为适当的默认值。如果没有为一个类编写构造器,就为为你提供一个无参构造器,这个构造器将所有字段设置为默认值。
如果类中至少提供了一个构造器,但是没有提供无参构造器,那么构造对象时就不能使用无参构造器。
-
调用构造器
关键字this指代一个方法的隐式参数,除此之外,还可以使用this来调用同一个类的其他构造器。
-
初始化块
除了在构造器中赋值和在声明中赋值,还可以使用初始化块,即类中的代码块。
构造器调用的具体处理步骤:
- 如果构造器的第一行调用了另一个构造器,则基于所提供的参数执行第二个构造器。
- 否则将所有数据字段初始化为默认值,按照在类声明中出现的顺序,执行所有字段初始化方法和初始化块。
- 执行构造器主体代码。
-
finalize方法
该方法在垃圾回收器清理对象之前调用,不要使用该方法来回收资源,因为并不能知道它什么时候调用而且它已被废弃。
类设计技巧
- 保证数据私有
- 一定要对数据进行初始化
- 不要在类中使用过多基本类型
- 不是所有字段都需要单独的字段访问器和字段更改器
- 分解有过多职责的类
- 类名和方法名要能体现它们的职责
- 优先使用不可变类
继承
子类和父类
关键字extends表示正在构造的新类派生于一个已存在的类,这个已存在的类称为超类、基类或父类;新类称为子类、派生类或孩子类。Java中不支持多继承。
-
方法重写
子类可以重写父类的方法,也可以通过关键字super调用父类的方法。
重写方法的方法签名必须和父类一致,返回值小于等于父类方法,抛出的异常类型小于等于父类方法,访问修饰符大于等于父类方法。
-
子类构造器
可以使用super调用父类的构造器,使用super调用构造器的语句必须是子类构造器的第一条语句。
如果子类的构造器没有显式地调用父类构造器,将自动调用父类无参构造器。如果父类没有无参构造器,在子类的构造器又没有显式调用父类的其他构造器,Java编译器就会报告错误。
this的两个作用:①隐式参数的引用。②调用该类的其他构造器。
super的两个作用:①调用父类的方法。②调用父类的构造器。
-
多态
在Java中对象变量是多态的,既可以引用本类型的对象,也可以引用子类的对象。
方法调用的过程:
- 编译器查看对象的声明类型和方法名。
- 编译器确定方法调用中提供的参数类型,这个过程称为重载解析。
- 如果