再看建構式


如果類別有繼承關係,在建構子類別實例後,會先進行父類別定義的初始流程,再進行子類別中定義的初始流程,也就是建構子類別實例後,會先執行父類別建構式定義的流程,再執行子類別建構式定義的流程。

建構式可以重載,父類別中可重載多個建構式,如果子類別建構式中沒有指定執行父類別中哪個建構式,預設會呼叫父類別中無參數建構式。如果你如下撰寫程式:

class Some {
    Some() {
        System.out.println("呼叫Some()");
    }
}
class Other extends Some {
    Other() {
        System.out.println("呼叫Other()");
    }
}

如果嘗試new  Other(),看來好像是先執行Some()中的流程,再執行Other()中的流程,也就是先顯示"呼叫Some()",再顯示"呼叫Other()"。很奇怪是吧!先繼續往下看,就知道為什麼了。如果想執行父類別中某建構式,可以使用super()指定。例如:

class Some {
    Some() {
        System.out.println("呼叫Some()");
    }
    Some(int i) {
        System.out.println("呼叫Some(int i)");
    }
}
class Other extends Some {
    Other() {
        super(10);
        System.out.println("呼叫Other()");
    }
}

在這個例子中,new Other()時,先呼叫了Other()版本的建構式,super(10)表示呼叫父類別建構式時傳入int數值10,因此就是呼叫了父類別中Some(int i)版本的建構式,而後再繼續Other()super(10)之後的流程。其實當你這麼撰寫時:

class Some {
    Some() {
        System.out.println("呼叫Some()");
    }
}
class Other extends Some {
    Other() {
        System.out.println("呼叫Other()");
    }
}

先前談過,如果子類別建構式中沒有指定執行父類別中哪個建構式,預設會呼叫父類別中無參數建構式,也就是等於你這麼撰寫:

class Some {
    Some() {
        System.out.println("呼叫Some()");
    }
}
class Other extends Some {
    Other() {
        super();
        System.out.println("呼叫Other()");
    }
}

所以執行new Other()時,是先執行Other()中的流程,而Other()中指定呼叫父類別無參數建構式,而後再執行super()之後的流程。

注意!this()super()只能擇一呼叫,而且一定要在建構式第一行執行。

那麼你知道以下為什麼會編譯錯誤嗎?

找不到建構式?


編譯器會在你沒有撰寫任何建構式時,自動加入沒有參數的預設建構式(Default constructor),如果自行定義了建構式,就不會自動加入任何建構式了。在上圖中,Some定義了有參數的建構式,所以編譯器不會再加入預設建構式,Other的建構式中沒有指定呼叫父類別中哪個建構式,那就是預設呼叫父類別中無參數建構式,但父類別中現在哪來的無參數建構式呢?因此編譯失敗了!

有些場合建議,如果定義了有參數的建構式,也可以加入無參數建構式,即使內容為空也無所謂,這是為了日後使用上的彈性,例如運用反射(Reflection)機制生成物件的需求,或者是繼承時呼叫父類別建構式時的方便。