类的复用一般分为,组合和继承.
7.1组合语法
创建对象引用的方法一般有4种:
1.在定义对象的地方.
2.在类构造器中
3.在正使用这对象之前,这种方法也成为惰性初始化.在生成对象不值得以及 不必每次都生成的情况下这种方法可以减少额外的负担.
4.使用实例初始化.
形式如下:
public class Foo {
//instance variable initializer 实例变量初始化器
String s = "abc";
//constructor 构造函数
public Foo() {
System.out.println("constructor called");
}
//static initializer 静态初始化器
static {
System.out.println("static initializer called");
}
//instance initializer 实例变量初始化器
{
System.out.println("instance initializer called");
}
public static void main(String[] args) {
new Foo();
new Foo();
}
}
使用实例初始化的意义:优先构造函数,每次调用构造函数,里面的初始化都会执行.如果一个类有多个构造函数,有需求是在每个构造函数里面都需要进行初始化,可以利用实例初始化来减少重复的代码;在匿名内部类中可以进行初始化,因为这个类根本没有构造函数.
7.2继承语法
7.2.1基类初始化
当创建了一个导出类(有继承基类的类)的时候,该对象已经包含了一个基类的子对象.该子对象和用基类直接创建的对象是一样的,区别在于基类子对象包装在对象内部,而直接创建的在外部.基类在导出类构造器可以访问他之前就已经初始化了.即使有时候导出类没有创建构造方法,编译器也会为你合成一个默认的造方法,该构造方法内部调用了基类造方法.
采用默认构造器:不需要带参数.编译器可以为导出类创建基类.
带参数的构造器:必须在每个构造器中显示的调用super()传递,或者不传参数.需要显示的调用基类的构造器.否则编译器无法编译通过.
7.3代理
代理是继承和组合之间的一种中庸之道.
确保正确清理,如果需要清理对象,最好编写自己的清理方法,不要使用finalize()
7.4名字屏蔽
子类可以创建和基类相同名字的方法,而形参不同.不会被认为是override,此时子类还能正确的调用基类同名不同参数的方法.但是如果是子类需要重写 @override 基类的方法,那必须是方法名和参数完全一致.修饰词可以比基类的权限放宽,但是不能缩减.比如 基类 protected void fo(){…} ,子类可以 把放宽protected 为 public 或者保持protected.
7.5protected关键字
protected 表示,对于类用户他是private 的,但是对于子用户或者是同一个包内的类来说,他是可见的.尽管可以创建protected域,但是最好还是改成private ,protected用来控制类的继承范根权限.
7.7向上转型(upcasting)
因为在继承关系上面,一般是子类继承基类如下图所示:把wind强制转化成Instrument的实例进行处理,叫做向上转型.
image.png
向上转型是一个较专一的类转化为一个比较通用的类,所以的安全的.因为所有的子类都具备基类可以被继承的方法.向上转型的过程类接口唯一可能发生的事情是丢失方法,而不是获取新的方法.
7.8final关键字
java final关键字含义存在细微的差别,但是都是表示”这是无法改变的”.不做任何改变可能处于两种理由:”设计和效率”,由于这两个原因相差很远,所以有可能final会被勿用.
可能用到final的3种情况: 类,方法,数据(变量)
final数据:有数数据恒定不变是很有用的,比如:
1.一个永不改变的编译时常量
2.一个在运行时被初始化的值,而你不希望改变他.(初始化时)
对于编译是常量,表示是在编译时进行计算式,减轻运行时的负担.在java中这写必须是基本类型,并且以final表示,在对这个常量定义是必须赋值.
空白final
java允许生成空白final ,即在定义的时候不初始化,但是必须在构造器执行完之前被初始化.也就以为着,可以在:
1.构造器内 2.实例化块中 3.静态块中 (初始化)
final参数
在参数中设置final参数,意味在方法内部无法修改参数引用所指向的对象.但是可以修改该对象内部的值(调用该对象的方法).如果是基本类型数据,那么该基本类型数据是无法被修改的.
final方法
使用final方法的原因:
1.把方法锁住,防止任何继承者修改.因为final方法是不能被重写(overriding)的.
2.早期的虚拟机为了提高新能,会把含有final关键字的方法,把方法内部的调用都编译成内嵌调用.但是后来的编译器和虚拟机已经优化了这种处理效率问题.程序不需要考虑这个优化.
final 和 private
final类中所有的方法都会隐式的制定为final,由于无法覆盖final 方法,所以也就无法取用private方法,所有子类也无法重写(overriding)他.对于有一种情况:类有private 的同名方法,子类也可以定义一个 同名的方法.但是这其实不是重写(overriding),只是子类定义了一个同名的新方法而已,和基类的方法不会冲突.覆盖(重写/overriding)只有在基类暴露出来的接口(可以被子类访问)的情况下才会出现呢.
出于某种原因,这个类永远不允许被继承
7.8.4有关final的建议
如果设计成final 方法,或者final 类时,需要考虑下是否会存在被复用的可能性.
网友评论