java虛擬機器規定必須立即初始化類的5種情況

sunjiaminaini發表於2017-08-09

Java類載入機制中,規定了有且僅有5種情況必須立即對類進行初始化(而載入,驗證,準備自然再次之前):
1. 遇到new,getstatic,putstatic和invokestatic這4條指令時,如果類沒有初始化時,必須初始化類。四條指令對應我們日常所見的 使用new關鍵字例項化物件,讀取一個類的靜態欄位,設定一個類的靜態欄位(被final修飾的靜態欄位除外,因為已在編譯期把結果放入常量池中了)和呼叫一個類的靜態方法。

2. 對類進行反射呼叫時。

3. 當初始化一個子類時,發現其父類沒有初始化,則需先出發其父類的初始化。

4. 當虛擬機器啟動時,一個類包含main()方法時,當前類需要初始化

5. 但是用動態語言支援時,如果一個java.lang.invoke.MethodHandle例項後解析結果REF_putStatic,REF_getStatic,REF_invokeStatic的方法控制程式碼時,當改方法控制程式碼對應的類沒有初始化時,需要初始化該類。(動態語言支援詳情請檢視)

初次之外所有引用類的地方都不會出發類初始化,被稱為被動應用,下面舉三個例子:

1. 通過子類應用父類靜態欄位,不會導致子類初始化,程式碼如下:

package com.sun.jojo.noinitclass;
public class SuperClass {
    static {
        System.out.println("SuperClass Init !!!");
    }
    public static int value = 123;
}

package com.sun.jojo.noinitclass;
public class SubClass extends SuperClass{
    static {
        System.out.println("SubClass Init !!!");
    }
}

package com.sun.jojo.noinitclass;
public class NotInitialization {
    public static void main(String[] args) {
        System.out.println(SubClass.value);
    }
}

結果:
SuperClass Init !!!
123

結果只輸出了”SuperClass Init !!!”, “SubClass Init !!!”沒有出來,對應靜態欄位,只有直接定義改欄位的類才會初始化。

2 .通過陣列定義來引用類,不會出發此類的初始化,程式碼如下:

package com.sun.jojo.noinitclass;
public class NotInitialization {
    public static void main(String[] args) {
        //System.out.println(SubClass.value);
        SuperClass[] superClasses = new SuperClass[10];
    }
}

執行結果並沒有列印出”SuperClass Init !!!”,這裡並沒有出發com.sun.jojo.noinitclass.SuperClass類的初始化.這裡觸發了另一個名為“[Lcom.sun.jojo.noinitclass.SuperClass”的類的初始化,他是虛擬機器自動建立的,直接繼承於java.lang.Object的子類,建立動作由位元組碼指令newarray觸發。

3.常量在編譯期間就會調入類的常量池中,本質上沒有直接引用的定義變數的類,因此使用常量欄位時不會觸發累的初始化。

public class ConstClass {
    static {
        System.out.println("ConstClass Init !!!");
    }
    public static final int value = 123;
}

public class NotInitialization {
    public static void main(String[] args) {
        //System.out.println(SubClass.value);
        //SuperClass[] superClasses = new SuperClass[10];
        System.out.println(ConstClass.value);
    }
}

結果:只列印出123 “ConstClass Init !!!”並沒有列印出來。

介面的初始化和類的初始化類似,區別在於5種中的第三種:當一個子類的初始化過程中需要去報其父類也必須先初始化,但介面初始化時不要求其父介面也進行初始化,只有在用到父介面時,才去初始化。

相關文章