在继承时,基础构造函数调用虚方法,为什么要对类进行Dervied并调用Dervied方法?

时间:2016-04-24 05:33:58

标签: java inheritance constructor

我遇到了一个问题。以下代码未按预期运行:

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类中的方法称为多态?

1 个答案:

答案 0 :(得分:2)

这就是我们永远不应该从构造函数调用虚方法的原因。运行构造函数时,有各个阶段。首先运行基类构造函数,然后运行派生类构造函数。

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

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

以下是Joshua Bloch的Effective Java - 第2版的相关引用:

  

超类构造函数在子类构造函数之前运行,所以   子类中的重写方法将在之前调用   子类构造函数已运行。如果重写方法取决于任何方法   初始化由子类构造函数执行,该方法将   不按预期行事。