回覆列表
  • 1 # 使用者990540253822

    類的生命週期:

    類從被載入到虛擬機器記憶體中開始,到卸載出記憶體結束。生命週期包括:載入、驗證、準備、解析、初始化、使用、解除安裝;其中驗證、準備、解析稱為連線。

    載入、驗證、準備、初始化、解除安裝,這幾個階段的順序是確定的,類的載入過程必須按照這個順序按部就班的開始;解析階段不一定,某些情況下可以在初始化階段之後再開始。

    必須立即對類進行 "初始化" 的5種情況(虛擬機器規範規定):

    注意:載入、驗證、準備階段必須在此之前開始

    1、遇到 new、getstatic、putstatic 或 invokestatic 這 4 條位元組碼指令時,如果沒有進行過初始化,需要先出發其初始化;

    生成這4條指令的最常見的 Java 程式碼場景是:使用 new 關鍵字例項化物件的時候;讀取、設定一個類的靜態欄位(被 final 修飾,已在編譯器把結果放入常量池的靜態欄位除外)的時候;呼叫一個類的靜態方法的時候。

    2、使用 java.lang.reflect 包的方法對類進行反射呼叫的時候,如果類沒有進行過初始化,需要先出發其初始化;

    3、當初始化一個類的時候,如果發現其父類還沒有進行過初始化,則需要先觸發其父類的初始化;

    4、當虛擬機器啟動時,使用者需要指定一個要執行的主類(包含 main() 方法的那個類),虛擬機器會先初始化這個主類;

    5、當使用 JDK 1.7 的動態語言支援時,如果一個 java.lang.invoke.MethodHandle 例項最後的解析結果 REF_getStatic、REF_putStatic、REF_invokeStatic 的方法控制代碼,並且這個方法控制代碼所對應的類沒有進行過初始化,則需要先觸發其初始化。

    這 5 中場景中的行為稱為對一個類的主動引用。另外,所有引用類的方式都不會觸發初始化,被稱為被動引用。

    被動引用示例:

    1、透過子類引用父類的靜態欄位,不會導致子類初始化;

    public class TestNotInit {

    public static void main(String[] args) {

    // 透過子類引用父類的靜態欄位,不會導致子類初始化

    System.out.println(SubClass.value);

    }

    }

    class SuperClass {

    public static int value = 500;

    static {

    System.out.println("super class init");

    }

    }

    class SubClass extends SuperClass {

    static {

    System.out.println("sub class init");

    }

    } 

    輸出結果如下:

    super class init

    500

    2、透過陣列定義來引用類,不會觸發此類的初始化;

    public class TestNotInit {

    public static void main(String[] args) {

    // 透過陣列定義來引用類,不會觸發此類的初始化

    SuperClass[] array = new SuperClass[10];

    }

    }

    class SuperClass {

    public static int value = 500;

    static {

    System.out.println("super class init");

    }

    }

    輸出結果如下(什麼都沒有輸出):

    3、常量在編譯階段會存入呼叫類的常量池中,本質上並沒有直接引用到定義常量的類,不會觸發定義常量的類的初始化。

    public class TestNotInit {

    public static void main(String[] args) {

    // 常量在編譯階段會存入呼叫類的常量池中,本質上並沒有直接引用到定義常量的類,不會觸發定義常量的類的初始化

    System.out.println(SuperClass.HELLO_WORLD);

    }

    }

    class SuperClass {

    public static final String HELLO_WORLD = "hello world";

    static {

    System.out.println("super class init");

    }

    }

    輸出結果如下:

    1

    hello world

    備註:介面與類真正有區別的是 第3條:當一個介面在初始化時,並不要求其父介面全部都完成了初始化,只有在真正用到父介面的時候(引用介面中定義的常量)才會初始化。

  • 中秋節和大豐收的關聯?
  • 脈衝電子圍欄原理圖及安裝步驟?