第七章 复用类
复用类的两种方式:①直接在类中创建另一个类的对象(组合)。②按照现有类来创建新的类(继承
)。
7.1 组合语法
编译器并不是每一次都为每一个引用创建对象,这样能够减少不少负担。初始化引用的位置如下:
- 在定义的地方
- 在构造器中
- 在使用的时候(惰性初始化),这样可以减少不必要的负担。
- 使用实例初始化(暂时分不清)
7.2 继承语法
- 继承使用
extends
关键字 - 每个类都可以创建
main
方法。但是被运行的那个文件的main
方法才会被调用。main
函数方便于单元测试。可以在一个类的main
方法中显式地调用另一个类的main
方法。 - 基类中包访问权限的变量和方法,只能被相同包的类访问,无法被其他包的类访问到。
- 在基类中可以覆盖基类方法,并通过
super
来调用基类的方法。
7.2.1 初始化基类
无参构造器的初始化顺序:系统会自动调用基类构造器,然后调用当前类的构造器。
有参构造器:需要显式调用。
7.3 代理–介于继承与组合之间
在代理类中组合对象,并定义新的函数调用组合类的方法。
7.4 继承与组合的结合使用
7.4.1 确保正确的清理
在必须要有的清理中,需要注意顺序(尤其有继承的时候)。
7.4.2 名称的屏蔽与@override
如果基类中有某个被多次重载的方法名称,那么在导出类重新定义并不会屏蔽基类中的任何版本。
@override可以提示不想冲在时发生了以外的重载。
7.5 继承与组合的选择
组合与继承都允许在新类中放置子对象,组合是显式的方式,继承是隐式的方式。
组合:在新类中想用现有类的功能而不是其接口。如汽车与其相关部件的组合。
继承:使用某个现有的类,开发其特殊版本来满足特殊化的需要。
7.6 protected关键字
在实际项目中,经常会将某些事物对外部隐藏,但仍需要对其导出类成员访问他们。(富翁希望把财产留给后代,而不是社会)
7.7 向上转型
继承的关系可以表述为“新类型是现有类的一种类型”。这不仅是一种华丽的概括,而且有语言具体的支撑。
由于继承类可以确保基类的方法在导出类同样有效,因此发送给基类的消息,继承类一样能接收到。
7.7.2 再讨论组合与继承
慎用继承:如果向上转型是必要的,则继承是必要的,否则应当考虑是否要继承。
7.8 final关键字
final
关键字表示“这是不可改变的”可以分三种情况:数据、方法、类
7.8.1 final 数据
应用场景
- 一个永不改变的编译常量。
- 一个在运行时被初始化的量,并且在之后不希望被改变。
注意点:
- 一个既是static又是final的变量只占据一段不饿能改变的内存空间。
- 当对象引用使用final修饰时,final使引用的值恒定不变。
7.8.1 final 方法
应用场景
- 设计方面:锁定方法,防止任何继承类修改它的含义,并且不会被覆盖。
- 效率方面:方法声明为final就是同意编译器将针对该方法的调用转为内嵌调用。当调用该方法时,会根据自己的判断,跳过插入程序而执行调用机制(将参数入栈,跳出方法代码处执行,然后回来清理栈中参数,处理返回值),并且以方法体中的实际代码副本来代替方法的调用。这将消除方法调用的开销。但是当方法很大,所带来的提升会因为花费方法内的时间量而被缩减。
注:在目前版本中,这一情况会被JVM探测处理,不需要final来优化了
final与private
类中所有方法都是隐式指定为final的。增加final并不会附加任何额外的意义。
7.8.3 final类
当某个类被声明为final时,就表明该类不打算被继承,并且也不允许别人这么做。
7.9 初始化及类的加载–包含static的情况
当创建对象或者调用static方法时就会发生初始化,并且定义为static的东西只会被初始化一次。
初始化顺序:按照基类的继承顺序进行依次加载。接下来根基类中的static初始化,然后是下一个导出类依次类推。这种方式很重要,因为导出类的static初始化很可能依赖于基类成员能否被正确初始化。
至此为止,必要的类的初始化加载完毕,对象可以被创建了。首先对象中的基本类型会被设置为默认值,对象引用被设置为null,然后基类构造器被调用(或者super调用)。
7.10 总结
组合与集成都能从现有的类中生成新的类。组合一般是将现有的类型作为新类型的一部分,而继承复用的是接口。
在继承时,由于导出类有基类的接口,因此可以向上转型,这对于多态至关重要。