Java有繼承時的初始化順序

public class Beetle extends Insect{
    private int k = print("Test.k initialized.");
    public Beetle() {
        System.out.println("k = " + k);
        System.out.println("j = " + j);
    }
    private static int x2 = print("static Test.x2 initialized.");
    public static void main (String[] args) {
        System.out.println("Beetle constructor.");
        Beetle t = new Beetle();
    }
}

class Insect {
    private int i = 9;
    protected int j;
    Insect() {
        System.out.println("i = " + i + ", j = " + j);
        j = 39;
    }
    Insect(int i) {
        System.out.println("Insect(int i)");
    }
    private  static int x1 = print("static Insect.x1 initialized.");
    static int print(String s) {
        System.out.println(s);
        return 47;
    }
}
得到的輸出結果爲:
static Insect.x1 initialized.
static Test.x2 initialized.
Beetle constructor.
i = 9, j = 0
Beetle.k initialized.
k = 47
j = 39

繼承基類的子類(以下簡稱子類)的對象創建的初始化過程如下:

1.加載子類的.class文件;

2.通過關鍵字得知子類有一個基類,繼續加載基類的.class文件;若基類還有它的上一層基類則會繼續加載;

3.static域的初始化是在類加載完之後就會進行的,最上一層基類加載完,該類的static域便會初始化,此時基類已加載完,static域也已經初始化完畢,再處理第二層基類的static域,對其進行初始化,直到最下層子類的static域初始化完成,此時子類及其所有基類的加載和static域已經初始化完成。

以上三步是在沒有創建對象,或者說子類的main方法裏沒有任何語句時都會執行的,只要運行子類,都會執行類的加載和靜態域的初始化。


在beetle上運行Java時,所發生的第一件事情就是試圖訪問Beetle.main(),於是加數器開始啓動井找出Beetle的編譯代碼
(在名爲 Beetle. class的文件之中)。在對它進行加載的過程中,編譯器注意到它有一個基類(這是由關鍵字 extends得知的),
於是它繼續進行加載。不管你是否打算產生一個該基類的對象,這都要發生(請嘗試將對象創建代碼註釋掉,以證明這一點)。

如果該基類還有其自身的基類,那麼第二個基類就會被加載,如此類推。接下來,根基類
中的 static初始化(在此例中爲 Insect)即會被執行,然後是下一個導出類,以此類推,這種方
式很重要,因爲導出類的static初始化可能會依賴於基類成員能否被正確初始化
至此爲止,必要的類都已加載完畢,對象就可以被創建了。首先,對象中所有的基本類型
都會設爲默認值,對象引用被設爲null,這是通過將對象內存設爲二進制零值而一舉生成的
然後,基類的構造器會被調用。在本例中,它是自動調用的。但也可以用super來指定對基類
構造器的調用(正如在Beetle構造器中的第一步操作)。基類構造器和導出類的約造器一樣,
以相同的順序來經歷相同的過程。在基類構造器完成之後,實例變量按其次序被初始化。最後
構遺器的其餘部分被執行。


故,在創建子類對象的時候,初始化順序爲:
加載文件初始化靜態數據–>基類非靜態數據初始化–>基類構造器(包括用super指明的,也是先於子類構造器執行)–>子類非靜態數據–>子類構造器


public class Beetle extends Insect{
    private int k = print("Beetle.k initialized.");
    public Beetle () {
        super(1);
        System.out.println("k = " + k);
        System.out.println("j = " + j);
    }
    private static int x2 = print("static Beetle.x2 initialized.");
    public static void main (String[] args) {
        System.out.println("Beetle constructor.");
        Beetle t = new Beetle ();
    }
}

class Insect {
    private int i = 9;
    protected int j;
    Insect() {
        System.out.println("i = " + i + ", j = " + j);
        j = 39;
    }
    Insect(int i) {
        System.out.println("Insect(int i)");
    }
    private  static int x1 = print("static Insect.x1 initialized.");
    static int print(String s) {
        System.out.println(s);
        return 47;
    }
}
static Insect.x1 initialized.
static Beetle.x2 initialized.
Beetle constructor.
Insect(int i)
Beetle.k initialized.
k = 47
j = 0

看清楚上面例子中,用super指明構造器時的初始化順序

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章