Java程序在啟動和運行時,需要首先完成初始化的工作。在涉及到繼承、static成員變量等因素時,初始化的順序就復雜起來。下面以一個例子說明繼承時的Java初始化順序。
## 例子:
~~~
class Insect{
private int i = 9;
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();
}
}
~~~
輸出:
~~~
static Insect.x1 initialized
static Beetle.x2 initialized
Beetle constructor
i = 9, j = 0
Beetle.k initialized
k = 47
j = 39
~~~
## 初始化詳細說明:
在Beetle上運行Java時,所發生的第一件事情就是試圖訪問Beetle.main()(一個static方法), 于是加載器開始啟動并找出Beetle類的編譯代碼(在名為Beetle.class的文件中)。在對它進行加載的過程中, 編譯器注意到它有一個基類(這是由關鍵字extends得知的),于是它繼續進行加載。不管你是否打算殘生一個該基類的對象,這都要發生( 請嘗試將對象創建代碼注釋掉,以證明這一點)。如果該基類還有其自身的基類,那么第二個基類就會被加載,如此類推。
接下來,根基類中的static初始化(在此例中為Insect)即會被執行,然后是下一個導出類,以此類推。
這種方式很重要,因為導出類的static初始化可能會依賴于基類static成員能否被初始化。
至此為止,必要的類都已加載完畢,對象就可以被創建了。首先是基類對象的創建,然后是下一個導出類對象創建,以此類推。
對于每一個對象的創建,首先對象中所有的基本類型都會被設為默認值,對象引用被設為null——這是通過將對象內存設為二進制零值而一舉生成的。
然后對象中的成員的顯示的初始化被執行。然后構造器會被調用,對象創建完畢。
(以上例子和說明來自于Java編程思想第四版,說明部分有一些是自己修改的,僅用于學習交流之用)