對於靜態變量、靜態初始化塊、變量、初始化塊、構造器,它們的初始化順序依次是(靜態變量、靜態初始化塊)>(變量、初始化塊)>構造器。咱們也能夠經過下面的測試代碼來驗證這一點:函數
public class InitialOrderTest { // 靜態變量 public static String staticField = "靜態變量"; // 變量 public String field = "變量"; // 靜態初始化塊 static { System.out.println(staticField); System.out.println("靜態初始化塊"); } // 初始化塊 { System.out.println(field); System.out.println("初始化塊"); } // 構造器 public InitialOrderTest() { System.out.println("構造器"); } public static void main(String[] args) { new InitialOrderTest(); } }
運行以上代碼,咱們會獲得以下的輸出結果:測試
這與上文中說的徹底符合。那麼對於繼承狀況下又會怎樣呢?咱們仍然以一段測試代碼來獲取最終結果:code
class Parent { // 靜態變量 public static String p_StaticField = "父類--靜態變量"; // 變量 public String p_Field = "父類--變量"; protected int i = 9; protected int j = 0; // 靜態初始化塊 static { System.out.println(p_StaticField); System.out.println("父類--靜態初始化塊"); } // 初始化塊 { System.out.println(p_Field); System.out.println("父類--初始化塊"); } // 構造器 public Parent() { System.out.println("父類--構造器"); System.out.println("i=" + i + ", j=" + j); j = 20; } } public class SubClass extends Parent { // 靜態變量 public static String s_StaticField = "子類--靜態變量"; // 變量 public String s_Field = "子類--變量"; // 靜態初始化塊 static { System.out.println(s_StaticField); System.out.println("子類--靜態初始化塊"); } // 初始化塊 { System.out.println(s_Field); System.out.println("子類--初始化塊"); } // 構造器 public SubClass() { System.out.println("子類--構造器"); System.out.println("i=" + i + ",j=" + j); } // 程序入口 public static void main(String[] args) { System.out.println("子類main方法"); new SubClass(); } }
運行一下上面的代碼,結果立刻呈如今咱們的眼前:對象
父類--靜態變量 父類--靜態初始化塊 子類--靜態變量 子類--靜態初始化塊 子類main方法 父類--變量 父類--初始化塊 父類--構造器 i=9, j=0 子類--變量 子類--初始化塊 子類--構造器 i=9,j=20繼承
如今,結果已經不言自明瞭。子類的靜態變量和靜態初始化塊的初始化是在父類的變量、初始化塊和構造器初始化以前就完成了。 靜態變量、靜態初始化塊,變量、初始化塊初始化了順序取決於它們在類中出現的前後順序。 執行過程分析 (1)訪問SubClass.main(),(這是一個static方法),因而裝載器就會爲你尋找已經編譯的SubClass類的代碼(也就是SubClass.class文件)。在裝載的過程當中,裝載器注意到它有一個基類(也就是extends所要表示的意思),因而它再裝載基類。無論你創不建立基類對象,這個過程總會發生。若是基類還有基類,那麼第二個基類也會被裝載,依此類推。 (2)執行根基類的static初始化,而後是下一個派生類的static初始化,依此類推。這個順序很是重要,由於派生類的「static初始化」有可能要依賴基類成員的正確初始化。 (3)當全部必要的類都已經裝載結束,開始執行main()方法體,並用new SubClass()建立對象。 (4)類SubClass存在父類,則調用父類的構造函數,你可使用super來指定調用哪一個構造函數(也就是Beetle()構造函數所作的第一件事)。 基類的構造過程以及構造順序,同派生類的相同。首先基類中各個變量按照字面順序進行初始化,而後執行基類的構造函數的其他部分。 (5)對子類成員數據按照它們聲明的順序初始化,執行子類構造函數的其他部分。it
補充 在第一次建立一個類的對象或其子類或第一次調用一個類的靜態屬性和方法的時候,會發生類加載,而後纔會有類的初始化的順序編譯