2016-04-24 74 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版:

父類的構造子類的構造函數之前運行,因此 的 子類的構造函數之前在子類中重寫方法將被調用跑。如果覆蓋方法取決於由子類構造函數執行的任何 初始化,則方法 的行爲不如預期。

相關問題