如果一個類A繼承自另一個類B,當建立這個A類的對象時,建構函式是怎樣運作的? 我們知道一個類繼承了另一個類後,這個類會包含父類的所有的執行個體變數和方法。也包括父類中的private執行個體變數,雖然在子類中無法直接存取父類中標記為private類型的執行個體變數,但是仍然可以通過父類中定義的GETTER與SETTER來進行操作。並且繼承自父類的一些其他方法也有可能會用到父類中的一些執行個體變數,如果父類中的執行個體變數沒有進行初始化,很可能進行A的初始化時會遇到問題,所以在我們初始化A類對象之前應該先對B類(父類)進行初始化。
public class Animal { public Animal() { System.out.println("I am making a new Animal"); }}public class Dog extends Animal { public Dog() { System.out.println ("I am making a new Dog"); }}public class TestDog { public static void main(String[] args) { System.out.println("I am Starting"); Dog d = new Dog(); }} // 這段代碼,當我們運行了 TestDog 類後 正確的輸出應該為 // I am Starting // I am making a new Animal // I am making a new Dog
可以看出,當我們建立Dog對象時首先完成了Animal類的構造方法,最後才完成了Dog類的構造方法,可以用棧來理解這個構造方法的調用,當我們new 一個 Dog 時,Dog()構造方法被壓入棧中,隨後Animal()構造方法被壓入棧中,實際上JAVA中所有類都繼承自Object,所以Object()構造方法也被壓入棧中,也就是棧的最頂層。然後首先完成了Object()構造方法,Object()從棧中彈出,再完成了Animal()構造方法並從棧中彈出,最後完成了Dog()構造方法並從棧中彈出,至此Dog對象的建立工作才算完成。
通過以上代碼及輸出可以看到,在Dog的建構函式運行時自動調用了它的父類Animal類的構造方法,而Animal構造方法實際上自動調用了Object類的構造方法。因為實際上JVM在我們每個構造方法的第一行添加了 super(); 這行語句。它的作用就是調用父類的構造方法,當然我們也可以手動調用super(),比如當父類的構造方法帶有參數時,我們可以使用super(xx, xx);在子類的構造方法中調用父類的構造方法,但是需要注意super()語句需要放在子類構造方法的第一行進行調用,否則會報錯。一旦我們自己手動調用了super() JVM將不再自動為我們添加 super() 的調用。
另外如果我有兩個或多個構造方法,當一個A構造方法只是對另一個B構造方法額外添加了一些處理,我們可能會想到代碼重用,我們可以在A構造方法中使用this(); 來調用B構造方法實現代碼重用。例如:
public class Dog {
int height;
public Dog() {
this(40);
// 這裡還可以做一些其他初始化處理
// ****** 我們需要注意,this 也必須放在構造方法中的第一行,還記得之前談到 super(); 也是要求放在第一行的,
// 所以 this(); 和 super(); 是不能同時使用的 ****************************************************************
}
public Dog( int newHeight ) {
height = newHeight;
}
}