Java類加載的過程詳解
Java:類加載過程
1.加載——3件事
- 1.通過全類名獲取定義此類的二進制字節流(eg:從jar、war中獲取);
- 2.將字節流所代表的靜態存儲結構轉換為方法區的運行時數據結構;
- 3.在內存中生成一個代表該類的Class對象,作為方法區這些數據的訪問入口。
2.連接
加載階段和連接階段的部分內容是交叉進行的,加載尚未結束,連接階段可能就開始運行瞭。
2.1.驗證
2.2.準備
準備階段:正式為類變量分配內存並設置類變量初始值的階段,這些內存在方法區分配。註意:
1.這時候進行內存分配的僅包括類變量(static),而不包括實例變量,實例變量會在對象實例化時隨著對象一塊分配在 Java 堆中;
2.除瞭含有final修飾的變量外,其他都賦值0,null,false這種的。
如下例子, value 的值就被復制為 111,而不是0.
public static final int value=111
2.3.解析
解析階段是虛擬機將常量池中的符號引用替換為直接引用的過程。
- 也就是得到類或者字段、方法在內存中的指針或者偏移量。
什麼是符號引用?
* 比如org.simple.People類引用瞭org.simple.Language類;
* 在編譯時People類並不知道Language類的實際內存地址,因此隻能使用符號org.simple.Language
3.初始化
初始化是類加載的最後一步,也是真正執行類中定義的 Java 程序代碼(字節碼),初始化階段是執行類構造器 < clinit >() 方法的過程。
對於< clinit >() 方法的調用,虛擬機會自己確保其在多線程環境中的安全性。因為 < clinit >() 方法是帶鎖線程安全,所以在多線程環境下進行類初始化的話可能會引起死鎖,並且這種死鎖很難被發現。
對於初始化階段,虛擬機嚴格規范瞭有且隻有5中情況下,必須對類進行初始化:
- 當遇到 new 、 getstatic、putstatic或invokestatic 這4條直接碼指令時,比如 new 一個類,讀取一個靜態字段(未被 final 修飾)、或調用一個類的靜態方法時。
- 使用 java.lang.reflect 包的方法對類進行反射調用時 ,如果類沒初始化,需要觸發其初始化.
- 初始化一個類,如果其父類還未初始化,則先觸發該父類的初始化。
- 當虛擬機啟動時,用戶需要定義一個要執行的主類 (包含 main 方法的那個類),虛擬機會先初始化這個類。
- 當使用 JDK1.7 的動態動態語言時,如果一個 MethodHandle 實例的最後解析結構為
REF_getStatic
、REF_putStatic
、REF_invokeStatic
、的方法句柄,並且這個句柄沒有初始化,則需要先觸發器初始化。
總結
本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!
推薦閱讀:
- java類加載機制、類加載器、自定義類加載器的案例
- 分析JVM的執行子系統
- Java類的加載時機
- 簡單易懂Java反射的setAccessible()方法
- Java11 中基於嵌套關系的訪問控制優化問題