2016-04-24 49 views
0

我遇到了问题。在继承时,基构造函数调用虚方法,为什么类是Dervied并调用Dervied方法?

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

字段不是多态的。 – Savior

回答

2

这就是为什么我们不应该从构造函数调用虚拟方法的原因。当构造函数运行时,有不同的阶段。首先运行基类构造函数,然后运行派生类构造函数。

因此,虚拟调用将取决于构造函数所在的阶段,最终可能会调用尚不存在的对象的方法。

这就是为什么您看到null被打印的原因,因为Derived中的'name'实例变量尚未初始化,因为基类构造函数正在运行并且它调用Derived类对象的tellName()。

这里是距离Joshua Bloch的Effective Java的相关报价 - 第2版:

父类的构造子类的构造函数之前运行,因此 的 子类的构造函数之前在子类中重写方法将被调用跑。如果覆盖方法取决于由子类构造函数执行的任何 初始化,则方法 的行为不如预期。

相关问题