前言
今天在看Android ContentProvider實作的時候,突然想到了Java類別在new的過程中,靜態域、靜態區塊、非靜態域、非靜態區塊、建構函數的執行順序問題。其實這是一個很經典的問題,非常檢視Java基礎知識的掌握度。很多面試過程中相信也有這樣的問題,趁著週末有時間複習一下。
結論
這裡先把整理好的結論丟給大家,然後我在寫個程式來驗證我們的結論。在Java類別被new的過程中,執行順序如下:
實作自身的靜態屬性和靜態程式碼區塊。 (依照程式碼出現的順序決定誰先執行)
實現自身的非靜態屬性和非靜態程式碼區塊。
執行自身的建構子。
在實作繼承的類別被new的過程中,初始化執行順序如下:
實作父類別的公共靜態屬性與靜態區塊層級程式碼。
實現自身的靜態屬性和靜態區塊級程式碼。
實作父類別的非靜態屬性和非靜態程式碼區塊。
執行父類別的建構子。
實現自身的非靜態屬性和非靜態程式碼區塊。
執行自身的建構子。
這裡需要簡單的介紹一下靜態程式碼區塊和非靜態程式碼區塊。
1. 靜態程式碼區塊:
static {
}
2.非靜態碼區塊
同點:都是JVM載入類別時且在建構函式執行之前執行,在類別中都可以定義多個,一般在程式碼區塊中對一些static變數進行賦值。
不同點:靜態程式碼區塊在非靜態程式碼區塊之前執行(靜態程式碼區塊 > 非靜態程式碼區塊)。靜態程式碼區塊只在第一次new時執行一次,之後不再執行。而非靜態程式碼區塊每new一次就執行一次。
驗證結論的最佳驗證就是寫出程式碼來進行結果證明。首先,先來看看無繼承的類別初始化時的執行順序,程式碼如下:
public class InitOderTest { public static String STATIC_FIELD = "静态属性"; // 静态块 static { System.out.println(STATIC_FIELD); System.out.println("静态代码块"); } public String field = "非静态属性"; // 非静态块 { System.out.println(field); System.out.println("非静态代码块"); } public InitOderTest() { System.out.println("无参构造函数"); } public static void main(String[] args) { InitOderTest test = new InitOderTest(); } }
執行結果:
靜態程式碼區塊
非靜態屬性
塊非靜態程式碼區塊 非靜態屬性塊。函數
接下來,我們驗證一下,當Java類別實作繼承後,執行順序是否和我們的結論吻合。測試程式碼如下:
class ParentTest { public static String PARENT_STATIC_FIELD = "父类-静态属性"; // 父类-静态块 static { System.out.println(PARENT_STATIC_FIELD); System.out.println("父类-静态代码块"); } public static String parentField = "父类-非静态属性"; // 父类-非静态块 { System.out.println(parentField); System.out.println("父类-非静态代码块"); } public ParentTest() { System.out.println("父类—无参构造函数"); } } public class InitOderTest extends ParentTest { public static String STATIC_FIELD = "静态属性"; // 静态块 static { System.out.println(STATIC_FIELD); System.out.println("静态代码块"); } public String field = "非静态属性"; // 非静态块 { System.out.println(field); System.out.println("非静态代码块"); } public InitOderTest() { System.out.println("无参构造函数"); } public static void main(String[] args) { InitOderTest test = new InitOderTest(); } }
執行結果如下:
父類別-靜態屬性
父類別-靜態程式碼區塊
靜態屬性
程式碼區塊
父類別—無參構造函數
非靜態屬性
非靜態程式碼區塊
無參構造函數
更多舉例說明Java中程式碼區塊的執行順序網相關文章請關注中文順序網相關文章!