多态,也称作动态绑定、后期绑定或运行时绑定。也就是说编译器一直不知道对象的类型,但方法调用机制能找到正确的方法体,并加以调用。
- 8.1 再论向上转型
把对某个对象的引用视为对其基类型的引用称做向上转型。
- 8.2 转机
将一个方法调用同一个方法主体关联起来称做绑定。
若在程序执行前进行绑定(如果有的话,由编译器和连接程序实现),叫做前期绑定。例如C只有一种方法调用,那就是前期绑定。
在运行时根据对象的类型进行绑定,称做后期绑定。也就是说编译器一直不知道对象的类型,但方法调用机制能找到正确的方法体,并加以调用。由此看出后期绑定机制必须保证在对象中有某种“类型信息”。
Java中除了static方法和final方法(private方法属于final方法)之外,其他所有的方法都是后期绑定。这意味着通常情况下,我们不必判定是否应该进行后期绑定——它会自动发生。
为什么要将某个方法声明为final呢?因为它可以防止其他人覆盖该方法。但更重要的一点或许是:这样做可以有效地“关闭”动态绑定,或者说,告诉编译器不需要对其进行动态绑定。这样,编译器就可以为final方法调用生成更有效的代码。然而,大多数情况下,这样做对程序的整体性能不会有什么改观。所以,最好根据设计来决定是否使用final,而不是出于试图提高性能的目的来使用final。
只有非private方法才可以被覆盖,域与静态方法都不具有多态性。(例:书156页左下角代码)
- 8.3 构造器和多态
构造器并不具有多态性(它们实际上是static方法,只不过该static声明是隐式的)。
在多态中,类的初始化过程是:
基类的构造器总是在导出类的构造过程中被调用,而且按照继承层次逐渐向上链接,以使每个基类的构造器都能得到调用。销毁的顺序则和初始化顺序相反,首先对其导出类进行清理,然后才是基类。
1).基类成员变量。 2).若基类构造器中调用了其他未初始化的对象,将分配给对象的存储空间初始化成二进制的零。 3).调用基类的构造器。 这个步骤会不断的反复递归下去,首先是构造器这种层次结构的根,然后是下一层导出类,等等,直到最底层的导出类。 4).按照声明顺序调用成员的初始化方法。 5).调用导出类构造器的主体。
- 8.4 协变返回类型
在导出类中的被覆盖的方法可以返回基类方法的返回类型的某种导出类型。
- 8.5 用继承进行设计
创建新类时首先考虑“组合”。具体根据具体情况设计。
向下转型不安全。