我們有必要對整個初始化過程有所認識,其中包括繼承,對這個過程中發生的事情有一個整體性的概念。請觀察下述代碼:
//: Beetle.java
// The full process of initialization.
class Insect {
int i = 9;
int j;
Insect() {
prt("i = " + i + ", j = " + j);
j = 39;
}
static int x1 =
prt("static Insect.x1 initialized");
static int prt(String s) {
System.out.println(s);
return 47;
}
}
public class Beetle extends Insect {
int k = prt("Beetle.k initialized");
Beetle() {
prt("k = " + k);
prt("j = " + j);
}
static int x2 =
prt("static Beetle.x2 initialized");
static int prt(String s) {
System.out.println(s);
return 63;
}
public static void main(String[] args) {
prt("Beetle constructor");
Beetle b = new Beetle();
}
} ///:~
該程序的輸出如下:
static Insect.x initialized static Beetle.x initialized Beetle constructor i = 9, j = 0 Beetle.k initialized k = 63 j = 39
對Beetle運行Java時,發生的第一件事情是裝載程序到外面找到那個類。在裝載過程中,裝載程序注意它有一個基礎類(即extends關鍵字要表達的意思),所以隨之將其載入。無論是否准備生成那個基礎類的一個對象,這個過程都會發生(請試著將對象的創建代碼當作注釋標注出來,自己去證實)。
若基礎類含有另一個基礎類,則另一個基礎類隨即也會載入,以此類推。接下來,會在根基礎類(此時是Insect)執行static初始化,再在下一個衍生類執行,以此類推。保證這個順序是非常關鍵的,因為衍生類的初始化可能要依賴於對基礎類成員的正確初始化。
此時,必要的類已全部裝載完畢,所以能夠創建對象。首先,這個對象中的所有基本數據類型都會設成它們的默認值,而將對象句柄設為null。隨後會調用基礎類構建器。在這種情況下,調用是自動進行的。但也完全可以用super來自行指定構建器調用(就象在Beetle()構建器中的第一個操作一樣)。基礎類的構建采用與衍生類構建器完全相同的處理過程。基礎順構建器完成以後,實例變量會按本來的順序得以初始化。最後,執行構建器剩余的主體部分。