前言
本文內容來源于《深入理解Java虛擬機》,各大電商平臺均可購買。
正文
類加載的時機
類加載的整個生命周期:
加載 - 驗證 - 準備 - 解析 - 初始化 - 使用 - 卸載
對于初始化階段,虛擬機嚴格規定只有5種情況必須立即對類初始化:
- 遇到new . getstatic、putstatic或invokestattic這4條字節碼指令時,如果類沒有初始化,則需要先觸發其初始化。常見場景:使用new創建對象,讀取或設置靜態字段(被final修飾,已在編譯期把結果放入常量池的靜態字段除外)的時候,以及調用一個類的靜態方法的時候。
- 使用java.lang.reflect的方法對類進行反射調用的時候,如果類沒有進行過初始化,則需要先觸發初始化;
- 當初始化一個類的時候,如果發現其父類還沒有進行過初始化,則需要先觸發其父類的初始化;
- 當虛擬機啟動時,用戶需要指定一個要執行的主類(包含main方法的類),虛擬機會先初始化這個主類;
- 當使用JDK 1.7的動態語言支持時,如果一個Java.lang.invoke.MethodHandle實例最后的解析結果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且這個方法句柄所對應的類沒有初始化,則需要先觸發其初始化。
類的加載過程
Java虛擬機中類的加載過程,也就是加載 - 驗證 - 準備 - 解析 - 初始化,這5個階段所執行的具體動作。
加載
在加載階段,虛擬機需要完成以下3件事情:
- 通過一個類的全限定名來獲取定義此類的二進制字節流;
- 將這個字節流所代表的靜態存儲結構轉化為方法區的運行時數據結構;
- 在內存中生成一個代表這個類的java.lang.Class對象,作為方法區這個類的各種數據的訪問入口;
驗證
這一階段的目的是為了確保Class文件的字節流中包含的信息符合當前虛擬機的要求,并且不會危害虛擬機自身的安全。
- 文件格式驗證:驗證字節流是否符合Class文件格式的規范,并且能夠被當前版本的虛擬機處理;
- 元數據驗證:對字節碼描述的信息進行語義解析,以保證其描述的信息符合Java語言規范的要求;
- 字節碼驗證:主要目的是通過數據流和控制流分析確定程序語義是合法的,符合邏輯的。在第二階段對元數據信息中的數據類型做完校驗后,這個階段將會類的方法體進行校驗分析,保證被校驗類的方法在運行時不會做出危害虛擬機安全的事件。
- 符號引用驗證:對類自身以外(常量池中的各種符號的引用)的信息進行匹配性校驗。
準備
準備階段是正式為類變量分配內存并設置類變量初始值的階段,這些變量所使用的內存都將在方法區中分配。
解析
- 類或接口的解析;
- 字段解析;
- 類方法解析;
- 接口方法解析;
初始化
類初始化階段是類加載過程的最后一步,前面的類加載過程中,除了在加載階段用戶應用程序可以通過自定義類加載器參與之外嗎,其余動作完全由虛擬機主導和控制。到了初始化階段買菜真正開始習性類中定義的Java程序代碼
雙親委派模型
使用不同的類加載對于instanceof等操作符的判斷有影響,例如加載同一個類,一個使用自定義類加載器,一個使用系統加載器,分別加載同一個類,互相判斷instanceof返回false。
為了解決這一問題,JDK在1.2引入了雙親委派模型,加載一個類,優先使用父加載器,保證同一個類優先使用頂端的父加載器。
image