最近在看Thinking in java,關於類別中的各成員初始化一直未曾關注,這裡記錄一下,如有錯誤,請指正:
#了解包含繼承的初始化全過程,以對所發生的一切有個全域性的把握,是很有益的。
在Java中,每個類別的編譯程式碼都存在於它自己的獨立的檔案中(即class檔案),而該檔案只在需要使用程式碼時才會載入。一般來說,“類別的程式碼在初次使用的時候才會載入”,這通常包含下面兩種情況:
創建類別的第一個物件的時候
存取static方法或欄位時
注意:第一次使用類別時,也是static初始化發生之處,所有物件和程式碼均依照書寫順序進行初始化,定義為static的欄位只會被初始化一次。
廢話不多說,詳細如下:
public class Base { //static字段 private static int I1 = printInt("Init I1"); //普通字段 private int i = 11; protected int j; public Base(){ System.out.println("Base constructor"); System.out.println("i="+i+" j="+j); j = 40; } static int printInt(String str) { System.out.println(str); return 10; } } public class Son extends Base{ private static int I2 = printInt("Init I2"); public Son() { System.out.println("Son constructor"); System.out.println("I2="+I2+" j= "+j); } public static void main(String[] args) { Son son = new Son(); } }
看完這段程式碼,你覺得輸出是什麼呢?
先給答案,在來分析:
Init I1 Init I2 Base constructori=11 j=0Son constructorI2=10 j= 40
程式先從Son類別的main方法入手,於是載入器開始啟動並找出Son編譯程式碼(即class檔案)。在進行載入中發現Son還有父類Base,於是繼續載入Base的編譯程式碼(如果Base還有父類則繼續向上執行),接下來,根基類的static欄位初始化,因為子類可能會依賴基類成員能否被正確初始化,所以發生了Init I1
, 然後往下到了Son,Son類別的static欄位初始化,於是發生了Init I2
,到此所有的必要的類別載入完成,可以開始初始化物件。看到Son son = new Son()
這行程式碼,準備呼叫Son的建構器,我們知道在繼承關係中,子類別的建構器中會呼叫super(),當然這裡是隱式調用。這樣又會回到父類別中去,不過在完成建構器之前,父類別(Base)中的所有普通字段(即非static字段)都會完成自己的初始化,所以會看到輸出i=11 j=0
,接著來到子類別(Son),和父類別的執行過程一樣,先完成普通欄位的初始化,再呼叫建構器方法。
說了一大堆,整體流程如下:
從程式入口開始,載入該類別(這裡設為Z類別),如有繼承關係遞歸向上,直到根類別(這裡假設A類別)。
完成A類別的static欄位初始化,遞歸向下,直到遇到Z類別。
完成A類別的普通域初始化,完成A類別的建構器,遞歸向下,直到遇到Z類別。
以上是淺談Java中各成員變數初始化流程的詳細內容。更多資訊請關注PHP中文網其他相關文章!