2017-08-02 50 views
2

當我打印printThread時,爲什麼打印0和3?子類方法的輸出不打印?

class Super { 

    Super() { 
     three(); 
    } 

    void three() { 
     System.out.println("three"); 
    } 
} 

class Child extends Super { 
    int three = (int) Math.PI; // That is, 3 

    void three() { 
     System.out.println(three); 
    } 

    public static void main(String[] args) { 
     Child t = new Child(); 
     t.three(); 
    } 
} 

輸出中是0和3 但它應該是3和3

+0

這是什麼語言?你的代碼片段甚至不應該編譯 – Lino

+0

你必須提供真實的代碼,否則我們無法幫你做任何事情。 – csmckelvey

+0

我剛剛編輯了代碼 – shiv

回答

1

當你調用new SomeType(..)然後在第一new與設立在字段創建SomeType類的實例其default values(爲int0,爲booleanfalse,對象引用null)。

對象的適當初始化過後通過構造函數代碼完成。這就是爲什麼負責初始化字段的代碼在每個構造函數開始時被移動(因爲子類中的代碼通常取決於超類的設置,因此調用super()之後)。因此,由於super()three域進行正確的初始化之前調用

class Child extends Super { 
    int three = (int) Math.PI; // That is, 3 

被編譯爲

class Child extends Super { 
    int three = 0;//initialization to proper value is moved to constructors 
        //         | 
    Child(){  //         | 
     super(); //         | 
     three = (int) Math.PI; //<--------------------+ 
    } 
    ... 
} 

,其價值仍然被設置爲0

超類的構造函數調用three();方法,但由於它在Child類中被覆蓋,因爲polymorphism,調用了Child#three的代碼。由於該代碼的打印值爲three,並且尚未進行正確的初始化,所以您首先會看到其默認值0(由new運算符設置)。

施工員完成工作後,您撥打three();第二次通過t.three();。此時three已正確初始化爲3(結果爲(int) Math.PI;),因此您會看到3


爲了避免這樣的問題,不要在構造函數中使用可以在子類中重寫的方法。直接使用字段,或使用私有,最終或靜態方法。

+0

這種情況下,會跟​​隨接口,因爲我們知道接口沒有建設者和接口的情況下如何發生? – shiv

+0

@shiv「界面不具有構造器」是真實的,但也不會忘記我們不能*實例化界面。我們只能實例化非抽象類,所以我不確定你在接口方面有什麼問題。 – Pshemo

+0

@shiv如果你想要的話,你可以詢問關於它的新的,單獨的後續問題,描述你的疑惑。 – Pshemo

0

如果通過這一步,three()永遠是子類的方法(你在Super實施將永遠不會被調用)。

此外,Super()three()第一次調用實際上構造函數的其餘部分之前Child第一次調用是0(子對象的不完全初始化還)運行,因此原因。