复用的两种方式:1)组合:在新的类中产生现有类的对象
2)继承:按照现有类的类型来创建新类。
3)代理:将基类对象作为代理类的成员,而代理类有对应于基类的所有方法,各方法内使用基类对象成员调用基类的方法。
7.1 组合语法
组合即将已有类的对象引用置于新类中。
在自定义类中定义toString()方法比较特殊,当编译器需要一个String而只有一个对象时,就会去调用该类对象的toString()。
例如:将一个String与一个对象相加,想得到一个新的String时,则编译器会试图去调用对象的toString()方法,然后再用toString()的返回值去与前面的String相连接。
类中域为基本类型时能够自动初始化为0,而对象引用被初始化为null。初始化引用的可选位置如下:
1)在定义类对象的位置
2)在类的构造器中
3)在使用这些对象之前(惰性初始化)
4)使用实例初始化
7.2 继承语法
同一个程序文件中可以为每一个类都创建一个main()方法,以便于测试。即使一个类只具有包访问权限,其public main()也是可以访问的。
继承规则:父类的所有数据成员指定为private,方法成员指定为public。
子类覆盖了父类的方法后,还是可以使用super再调用父类的该方法。
7.2.1 初始化基类
1)在创建子类对象时,会在其内部包装有一个基类子对象,而此时只有一种方法对基类子对象进行初始化,就是在子类的构造器中调用基类的构造器。
2)在子类构造器执行前,必然会先去自动执行基类的构造器。 此时初始化的顺序为:
- 父类--静态变量或静态初始化块(静态变量和静态初始化块先后由其出现顺序决定。但静态初始化引用的静态变量,必须在其前面先定义)
- 子类--静态变量或静态初始化块
- 子类static主函数内部(new 之前)
- 父类--普通变量或普通初始化块(new 以后,普通变量和普通初始化块先后由其出现顺序决定。但普通初始化引用的静态变量,必须在其前面先定义,包括父类的private数据成员也都会被初始化!!!,而且子类以后可以通过基类的public方法去访问它)
- 父类--构造器
- 子类--普通变量或普通初始化块
- 子类--构造器
继承体系的类加载,static型的不管是static变量,还是static代码块都是属于类的.顺序嘛谁在前面先初始化谁.
类加载完毕,才会开始准备生成继承体系的对象,从顶层类开始Object,非static变量,非static代码块,构造器的调用,一个父类的对象出来了,处于可用状态,马上开始下一级的对象的生成工作,一直到没有子类的那个类的对象生成出来.
对象生成工作OVER!
初始化的实际上在其他任何事物发生之前,将分配给对象的存储空间初始化成二进制的零
3)如果基类没有不带参数的默认构造器,或者想调用基类的带参数构造器,就必须在子类的构造器第一行用super(参数列表)来调用。
7.3 代理
将基类对象作为代理类的成员,而代理类有对应于基类的所有方法,各方法内使用基类对象成员调用基类的方法。
7.4 结合使用组合和继承
7.4.1 确保正确清理
必须将清理动作置于finally子句中,以预防异常的出现。finally子句表示:无论发生什么事,一定要为执行其内部语句。
清理顺序是:先执行子类的所有清理动作,顺序与生成相反,完了以后再执行父类的清理动作。
7.4.2 名称屏蔽
子类引入对父类的方法重载,完全可以与父类其他方法同时使用。而子类覆盖父类的方法后,还可以使用super来调用父类同名方法。
7.5 在组合与继承之间的选择
组合通常用于想在新类中使用现有类的功能而非它的接口这种情形
继承用于使用某个现有类,开发一个它的特殊版本。
7.6 protoected关键字
用于控制类的继承者的访问权限
7.7 向上转型
将子类引用作为实参,传给基类形参,即是向上转型。
注意:基类中的形参虽然声明的类型时基类,但是实际上是子类对象,即调用重载方法时,实际优先使用的是子类的。
当必须使用向上转型时,就要使用继承,否则可以选择组合。
7.8 final关键字
7.8.1 final数据
1) 当数据是编译期常量时,编译器就可以将其在编译期执行计算式时,直接代入,以减轻运行期负担
在Java中,此种常量必须是基本数据类型,在其前加final,而且在定义时就进行赋值。
2) 一个既是static,又是final的域只占据一段不能改变的存储空间。
对于基本类型,final使数值不变,而对于引用,无法再使其指向另一个对象,而对象本身是可以改变的。
3)当一个final域在运行期才能确定初值,它就无法成为编译期常量。
带有恒定初始值的final static基本类型全用大写字母命名,字间用下划线隔开。
对于static的final域,则每个对象该域都相同。而普通final则各对象不同。
4)对于final数组,与引用相同,只是指定的存储地址不可改变,而地址内的变量就可以改变。
空白final
声明为final但又未在定义处给定初值的数据成员。但在构造器中一定要初始化。
final参数
参数列表中指明为final后,则无法在方法中更改参数值。
7.8.2 final方法
基类的final方法可以被继承,但是无法被子类重载或覆盖。
同时编译器将该方法转为内嵌调用,提供效率。
final和private
类中所有的private方法都隐含为final方法。子类即使有与父类private方法相同签名的函数,也不是重载或者覆盖,而是一个新方法。因为基类的private方法根本就不是子类能知道的接口。
7.8.3 final类
不可被继承。其成员可是可不是final的。
7.9 初始化及类的加载
类只在第一个对象被构建或者第一次访问类的staitc数据或方法时,才被加载,且只加载一次。加载第一步即static数据初始化。
7.10 总结
复用应优先考虑使用组合,继承只是复用接口,而组合更灵活。