我遇到了一个问题。以下代码未按预期运行:
public class Dervied extends Base {
private String name = "dervied";
public Dervied() {
System.out.println(this.getClass().toString());
this.tellName();
}
public void tellName() {
System.out.println("Dervied tell name: " + name);
}
public static void main(String[] args) {
Base base = new Dervied();
}
}
class Base {
private String name = "base";
public Base() {
System.out.println(this.getClass().toString());
this.tellName();
}
public void tellName() {
System.out.println("Base tell name: " + name);
}
}
结果是:
class Dervied
Dervied tell name: null
class Dervied
Dervied tell name: dervied
但为什么呢?环境是jdk1.8.0_60和Windows 10.当new Dervied()
遇到Dervied()
方法时,调用基础构造函数Base()
。但为什么Base()
中的印刷版是Dervied
?并且this.tellName()
将Dervied
类中的方法称为多态?
答案 0 :(得分:2)
这就是我们永远不应该从构造函数调用虚方法的原因。运行构造函数时,有各个阶段。首先运行基类构造函数,然后运行派生类构造函数。
因此,虚拟调用将取决于构造函数所处的阶段,并且最终可能会调用尚不存在的对象上的方法。
这就是为什么你看到null被打印的原因,因为' name' Derived中的实例变量尚未初始化,因为基类构造函数正在运行,它调用Derived类对象的tellName()。
以下是Joshua Bloch的Effective Java - 第2版的相关引用:
超类构造函数在子类构造函数之前运行,所以 子类中的重写方法将在之前调用 子类构造函数已运行。如果重写方法取决于任何方法 初始化由子类构造函数执行,该方法将 不按预期行事。