对于有继承关系的类体系,Java中规定了成员初始化非静态成员和构造函数执行的顺序:
1、初始化父类非静态成员
2、执行父类构造方法
3、初始化子类非静态成员
4、执行子类构造方法
因此,我们似乎可以简单的总结出一个规律:对于同一个对象来说,其非静态成员在构造函数前初始化。
可下面代码的运行结果,并不符合以上预期。
public abstract class Base {
public Base() {
doSomething();
}
protected abstract void doSomething();
}
public class Derived extends Base {
private String varChild = "CHILD";
Derived() {
super();
}
@Override
protected void doSomething() {
System.out.println("variable in derived: " + varChild);
}
public static void main(String args[]) {
new Derived();
}
}
运行结果为:
variable in derived: null
而不是:
variable in derived: CHILD
这是因为:
在语言设计的时候,“在构造函数中调用虚函数”是个两难的问题。
如果调用的是父类的函数的话,这个有点违反虚函数的定义。
如果调用的是子类的函数的话,这可能产生问题的:因为在构造子类对象的时候,首先调用父类的构造函数,而这时候如果去调用子类的函数,由于子类还没有构造完成,子类的成员尚未初始化,这么做显然是不安全的。
C++选择了第一种,而Java选择了第二种。
进而,Scott Meyers在Effective C++ 条款9中指出:Never call virtual functions during construction or destruction。
更多讨论可以参考下面这篇文章: