第8章 多态
8.2 转机
- Java中除了static, final & private(private归为final一类)方法,都是动态绑定。
- 域同样是静态绑定。
8.3 构造器和多态
8.3.3 构造器内部的多态方法的行为
在C++中,应该避免在构造函数中调用virtual方法,因为这样的结果可能不是你想要的。
同样在Java中,应当避免在构造器中调用static, final或者private以外的方法。
如果在基类的构造器中调用了被导出类覆盖的方法,实际上是动态绑定在起作用,也就是基类中调用了导出类的行为。
1 import static java.lang.System.out; 2 class Base { 3 void draw() { 4 out.println("Base draw()"); 5 } 6 Base(){ 7 out.println("Base constructor start"); 8 draw(); 9 out.println("Base constructor end"); 10 } 11 } 12 13 public class Derive extends Base { 14 private int i = 3; 15 void draw() { 16 out.println("Derive draw() i = " + i); 17 } 18 Derive(){ 19 out.println("Derive constructor start"); 20 draw(); 21 out.println("Derive constructor end"); 22 } 23 public static void main(String args[]){ 24 new Derive(); 25 } 26 }/* Output: 27 Base constructor start 28 Derive draw() i = 0 29 Base constructor end 30 Derive constructor start 31 Derive draw() i = 3 32 Derive constructor end 33 */
在前面的章节中也提到过这个顺序:首先是类加载(自低向上)(类加载的过程包括abstract class但不包括interface,详细请参见第9章 接口),类加载(其实是Class的某个对象)的时候进行连个动作:分配空间,所有空间初始为空(Native为0,引用为Null,Boolean为False);其次调用域默认初始化和域初始化块,构造函数的调用,这个过程是自顶向下的,先基类再导出类。需要注意的是,因为在类加载后,方法的动态绑定就已经完成了,所以在第二部初始化(或者是初始化块,或者是构造函数,或者是域的默认初始化)中的函数调用都是动态绑定,也就造成了基类的初始化过程中,可以调用导出类的函数行为。
再次:应该避免这种使用方法!