繼承與初始化
- 2021 年 4 月 14 日
- 筆記
- Java編程思想, 有繼承時的初始化順序
了解包括繼承在內的初始化全過程:
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文件中):
- 在載入的過程中,編譯器注意到Beetle類有一個基類(這是由關鍵字extends得知的),於是載入器就會去載入這個基類。
- 如果基類還有其自身的基類,那麼第二個基類就會被載入,如此類推,直到找到根基類。
- 找到根基類後,就會執行根基類中的靜態初始化(在上例中為Insect類),然後是下一個導出類的靜態初始化,以此類推。採用這種由上至下的初始化方式,是因為導出類的靜態初始化可能依賴於基類成員是否被正確初始化。
至此為止,必要的類都已經載入完畢,對象就可以被創建了:
- 首先,對象中所有的基本類型成員都會被設為默認值,對象引用被設置為null——這是通過將對象記憶體設為二進位0值而一舉生成的;
- 然後,基類的構造器會先被調用;
- 在基類的構造器完成後,實例變數按其次序被初始化(普通初始化);
- 最後,本類構造器的其餘部分被執行。
當有繼承關係時,類成員的初始化順序為:
基類構造函數 > 靜態成員變數 = 靜態程式碼塊 > 非靜態成員變數 = 非靜態程式碼塊 > 構造函數
相關內容:(->)類成員變數的初始化