繼承與初始化

了解包括繼承在內的初始化全過程:

class Insect {
    private int i = printInit("Insect.i initialized");;
    protected int j;

    Insect() {
        System.out.println("i= " + i + ", j= " + j);
        j = 39;
    }

    private static int x1 =
            printInit("static Insect.x1 initialized");

    static int printInit(String s) {
        System.out.println(s);
        return 47;
    }
}

public class Beetle extends Insect {
    private int k = printInit("Beetle.k initialized");

    public Beetle() {
        System.out.println("k= " + k);
        System.out.println("j= " + j);
    }

    private static int x2 =
            printInit("static Beetle.x2 initialized");

    public static void main(String[] args) {
        System.out.println("Beetle constructor");
        Beetle b = new Beetle();
    }
}

 

執行結果:

"C:\Program Files\Java\jdk1.8.0_91\bin\java.exe" ...
static Insect.x1 initialized
static Beetle.x2 initialized
Beetle constructor
Insect.i initialized
i= 47, j= 0
Beetle.k initialized
k= 47
j= 39

Process finished with exit code 0

 

程式運行時,先試圖訪問Beetle.main()(一個static方法),訪問Beetle類的靜態方法將會使Beetle類載入,即載入器開始啟動並找出Beetle類的編譯程式碼(在名為Beetle.class文件中):

  1. 在載入的過程中,編譯器注意到Beetle類有一個基類(這是由關鍵字extends得知的),於是載入器就會去載入這個基類。
  2. 如果基類還有其自身的基類,那麼第二個基類就會被載入,如此類推,直到找到根基類。
  3. 找到根基類後,就會執行根基類中的靜態初始化(在上例中為Insect類),然後是下一個導出類的靜態初始化,以此類推。採用這種由上至下的初始化方式,是因為導出類的靜態初始化可能依賴於基類成員是否被正確初始化。

至此為止,必要的類都已經載入完畢,對象就可以被創建了:

  1. 首先,對象中所有的基本類型成員都會被設為默認值,對象引用被設置為null——這是通過將對象記憶體設為二進位0值而一舉生成的;
  2. 然後,基類的構造器會先被調用;
  3. 在基類的構造器完成後,實例變數按其次序被初始化(普通初始化);
  4. 最後,本類構造器的其餘部分被執行。

 

當有繼承關係時,類成員的初始化順序為:

基類構造函數 > 靜態成員變數 = 靜態程式碼塊 > 非靜態成員變數 = 非靜態程式碼塊 > 構造函數

 

相關內容:(->)類成員變數的初始化