来源于Think In Java中文第四版的162页,构造器内部的多态方法的行为相关内容
在多态性中有这样一个问题,如果在一个构造器的内部调用正在构造的对象的某个动态绑定方法(在父类构造器中调用子类覆写的方法),会发生什么情况?
在一般的方法内部,动态绑定的调用是运行时才决定的,因为对象不知道它是属于方法所在的类还是所在类的衍生子类。如果在构造器内部调用一个动态绑定的方法,那么就会用到这个方法被覆写后的实例。
通过实例代码来看一下
public class PloyConstructors {
public static void main(String[] args) {
new RoundGlyph(4);
}
}
class Glyph{
void draw(){
System.out.println("Glyph draw: ");
}
Glyph(){
System.out.println("Glyph before draw()");
//考虑动态绑定的问题在父类中如果某种情况下
//调用被子类覆写的方法,会发生什么?
draw();
System.out.println("Glyph after draw()");
}
}
class RoundGlyph extends Glyph{
private int radius = 1;
RoundGlyph(int r){
//super();
radius = r;
System.out.println("RoundGlyph.RoundGlyph,radius " + radius);
}
//通常情况下子类覆写父类方法获得多态性
@Override
void draw(){
System.out.println("RoundGlyph.draw(),radius " + radius);
}
}
其执行输出是
Glyph before draw()
RoundGlyph.draw(),radius 0
Glyph after draw()
RoundGlyph.RoundGlyph,radius 4
显然的,上面发生了我们不希望看见的结果,调用draw()方法输出了一个既不是1也不是4的值,这个值是未知的。
我们需要知道的是初始化的实际过程
1.存储空间被分配出来准备创建一个类实例,存储空间被初始化为0
2.调用父类构造器,初始化父类对象,这时会调用被覆盖的draw()方法,由于步骤1,此时radius=0
3.调用成员的初始化部分
4.调用子类的构造器
因为构造器内部的多态方法的行为特点,所以使用除了不会被覆写的final方法,我们在构造器中应该避免一些调用将来有可能被覆写的方法甚至不要调用任何方法.