父类构造器中调用子类覆写方法问题
父类
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) {
radius = r;
System.out.println("RoundGlyph.RoundGlyph(), radius = " + radius);
}
@Override
void draw() {
System.out.println("RoundGlyph.draw(), radius = " + radius);
}
}
public class PolyConstructors {
public static void main(String[] args) {
new RoundGlyph(5);
}
}
执行结果:
Glyph() before draw()
RoundGlyph.draw(), radius = 0
Glyph() after draw()
RoundGlyph.RoundGlyph(), radius = 5
上面的代码虽然能够执行成功!但是存在一个问题:RoundGlyph.draw(), radius = 0。
这一行结果中radius = 0在我们的代码中并没有出现,但是执行结果出现了!
分析:
在PolyConstructors类中,通过“new RoundGlyph(5);”建立RoundGlyph的实例对象,首先会先初始化父类对象Glyph,即默认调用父类的无参构造:“new Glyph();”,此时在父类的无参构造中,调用了draw()方法,但是实际上父类的无参构造中的draw()方法调用的是子类覆写的draw()方法。这就引出了一个问题:子类在初始化时,父类会先于子类初始化,而父类构造器中调用的方法又是子类覆写的方法,从而导致了父类在初始化过程中使用了错误的子类初始化数据。
因此,编写构造器时:做尽量少的事让对象进入良好状态。如果有可能的话,尽量不要调用类中的任何方法。在基类的构造器中能安全调用的只有基类的final 方法(这也适用于可被看作是 final 的 private 方法)。这些方法不能被重写,因此不会产生意想不到的结果。