JVM類載入初學一
一個類從被載入進虛擬機器記憶體開始,到卸載出記憶體,生命週期分為七個階段:載入->驗證->準備->解析->初始化->使用->解除安裝。
其中驗證、準備和解析這3個階段被統稱為連線。載入、驗證、準備、初始化和解除安裝這5個階段的先後順序是固定的。解析這一階段可以在初始化階段之後進行,這是為了支援java語言的執行時繫結(動態繫結)。
對於在什麼時候開始類載入的第一個階段,java虛擬機器並沒有強制約束。但是有5種場景之下,是要必須進行類的初始化,而在初始化之前,就相應的要完成載入、驗證、準備的階段:
1.當虛擬機器啟動時,使用者需要指定一個執行的主類(即包含main()方法的類),虛擬機器會初始化該主類;
2.遇到new、getstatic、putstatic、invokestatic4個位元組碼指令時,如果類沒有進行過初始化,則需要先進行該類的初始化。這4條位元組碼的主要場景為當使用new關鍵字例項化物件時、讀取或設定一個類的靜態屬性以及呼叫一個類的靜態方法時;
3.初始化一個類的時候,如果該類的父類還未進行過初始化,則先進行父類的初始化;
4.使用java.lang.reflect包進行類的反射呼叫的時候,如果類還未進行初始化,則先進行類的初始化;
5.當使用JDK1.7的動態語言支援的時候,如果java.lang.invoke.MethodHandle例項最後的解析結果REF_getStatic、REF_putStatic、REF_invokeStatic的方法控制代碼,並這個方法控制代碼所對應的類沒有經歷過初始化,則先觸發其的初始化。
example1.
輸出結果為SuperClass init。對於靜態欄位,只有定義這個欄位的類才會被初始化,子類引用父類定義的靜態欄位只會觸發父類的初始化,不會觸發子類的。
example2.
使用陣列定義類引用類的時候,不會觸發該類的初始化。
example3.
執行之後也沒有輸出ConstClass init。因為程式碼在編譯階段已經通過常量傳播優化,將常量值"hello world"儲存到NotInitialization類的常量池之中,所以對ConstClass.HELLOWORLD的引用都轉化為了對自身常量池常量的引用,兩個類在編譯過後就沒有了相互聯絡。
而介面的必須初始化和類的必須初始化唯一場景不同的是在初始化子類的時候,類要求父類已全部初始化完成,而介面則不需要父介面全部初始化完成,只有當真正使用到父介面的時候才會要求進行父介面的初始化。
轉載於:https://my.oschina.net/betteru/blog/2980508