2013-02-01 203 views
6

我非常困惑重寫構造函數。構造函數不能被覆蓋的是結果,當我在谷歌搜索它是什麼讓我的問題是覆蓋構造函數

public class constructorOverridden { 

    public static void main(String args[]) { 
     Sub sub = new Sub(); 
     sub.test(); 
    } 
} 

class Super { 
    Super() { 
     System.out.println("In Super constructor"); 
     test(); 
    } 

    void test() { 
     System.out.println("In Super.test()"); 
    } 
} 

class Sub extends Super { 
    Sub() { 
     System.out.println("In Sub constructor"); 
    } 

    void test() { // overrides test() in Super 
     System.out.println("In Sub.test()"); 
    } 
} 

當我運行此我得到的結果作爲

In Super constructor 
In Sub.test() 
In Sub constructor 
In Sub.test() 

請注意在子類中的測試方法被執行。它是否顯示超類構造函數被覆蓋。它是否正確?

回答

19

構造函數不是多態的 - 你不需要覆蓋它們。您在子類中創建了新的構造函數,並且每個子類構造函數都必須鏈接(可能間接)到超類構造函數。如果您沒有明確地鏈接到構造函數,則會在子類構造函數主體的開始處插入對無參數超類構造函數的隱式調用。

現在在重寫方法 - 一個對象從一開始就是它的「最終類型」,包括執行超類構造函數時。因此,如果您在Super構造函數代碼中打印getClass(),則在輸出中仍會看到Sub。其結果是被調用的覆蓋方法(即Sub.test),即使Sub構造函數尚未執行。

這基本上是一個壞主意,你應該總是避免構造函數調用可能-重寫方法 - 或文檔很清楚,這將是情況(這樣子類代碼意識到它可以」不依賴於已經適當初始化的變量等)。

+0

那麼,在避免「在構造函數中調用重載方法」時應該使用什麼方法?我試圖完成的是超類構造函數調用抽象方法init(),build()和fill()的基本流程。所以,所有的子類都必須經歷相同的流程! – Akshat

+0

@Akshat:好吧,這聽起來像是屬於「非常明顯的文檔」類別。通常有一些*設計的方式,但很難給出一個通用的配方。 –

+0

如果你可以給這些方式鏈接,那會很棒! – Akshat

3

構造函數的第一個隱含行是對Super()的調用。這就是爲什麼你得到這些結果。

3

這是正確的。在實例化子類時,首先調用超類構造函數,然後調用層次結構中的每個連續構造函數。

在上例中,超類構造函數調用覆蓋的方法(test())。這是有效的,但是由於沒有調用子類的構造函數,所以潛在的危險,並且你的子類不會被完全初始化。由於這個原因,在構造函數中調用重寫的(或可重寫的)方法並不是很好的做法。

2

它不覆蓋超類的構造函數,構造函數不能被覆蓋它可以被重載。

當你創建子類對象時,超類將首先被​​實例化,然後子類將被實例化。它像沒有父母的孩子不能存在

編譯器會自動從子類構造函數中調用超類構造函數。

Sub() { 
    super(); 
    System.out.println("In Sub constructor"); 
} 
4

您不能重寫構造函數,因爲構造函數是由它構造的類的名稱調用的。你怎麼能用相同的構造函數創建一些不同的類?另外,子類不會從其父類繼承構造函數。

如果父類的構造做了一些重要的初始化,可以從孩子的構造使用超叫:

class Err extends Throwable { 
    Err(String message) { 
     super(message); // Call the constructor of Throwable. 
     .. 

父類的構造也總是叫。如果你自己沒有調用任何方法,那麼在輸入派生類的構造函數之前會自動調用一個不帶參數的構造函數。如果父項沒有無參數構造函數,並且沒有調用任何構造函數,則會報告編譯時錯誤。