1. 程式人生 > >JVM當中的類載入

JVM當中的類載入

類載入機制

不同於其他Java基礎知識,類載入機制我們可能接觸得比較少,之前我們瞭解到Java原始碼先是被編譯成class位元組碼,最終需要載入到虛擬機器中才能執行。

整個生命週期包括:載入、驗證、準備、解析、初始化5個階段。

其中載入指的是將類的.class檔案中的二進位制資料讀入到記憶體中,將其放在執行時資料區的方法區內,然後在堆區建立一個java.lang.Class物件,用來封裝類在方法區內的資料結構。類的載入的最終產品是位於堆區中的Class物件,Class物件封裝了類在方法區內的資料結構,並且向Java程式設計師提供了訪問方法區內的資料結構的介面。

載入:查詢並載入類的二進位制資料

1、通過一個類的全限定名獲取描述此類的二進位制位元組流;
2、將這個位元組流所代表的靜態儲存結構儲存為方法區的執行時資料結構;
3、在java堆中生成一個代表這個類的java.lang.Class物件,作為訪問方法區的入口;

 

驗證:確保被載入的類的正確性

檔案格式驗證:驗證位元組流是否符合Class檔案格式的規範;例如:是否以0xCAFEBABE開頭、主次版本號是否在當前虛擬機器的處理範圍之內、常量池中的常量是否有不被支援的型別。

元資料驗證:對位元組碼描述的資訊進行語義分析(注意:對比javac編譯階段的語義分析),以保證其描述的資訊符合Java語言規範的要求;例如:這個類是否有父類,除了java.lang.Object之外。

位元組碼驗證:通過資料流和控制流分析,確定程式語義是合法的、符合邏輯的。

符號引用驗證:確保解析動作能正確執行。

 

準備:為類的靜態變數分配記憶體,並將其初始化為預設值。

假設一個類變數的定義為:public static int value = 3;

那麼變數value在準備階段過後的初始值為0,而不是3,因為這時候尚未開始執行任何Java方法,而把value賦值為3的putstatic指令是在程式編譯後,存放於類構造器<clinit>()方法之中的,所以把value賦值為3的動作將在初始化階段才會執行。

 

解析:把類中的符號引用轉換為直接引用

1、符號引用使用一組符號來描述所引用的目標,可以是任何形式的字面常量,定義在Class檔案格式中。
2、直接引用可以是直接指向目標的指標、相對偏移量或則能間接定位到目標的控制代碼。

 

初始化:為類的靜態變數賦予正確的初始值

JVM中只有5種情況必須對類進行初始化

 

以下幾種情況,不會觸發類初始化

1.通過子類引用父類的靜態欄位,只會觸發父類的初始化,而不會觸發子類的初始化。

  • 執行new、getstatic、putstatic和invokestatic指令;
  • 使用reflect對類進行反射呼叫(如Class.forName);
  • 初始化一個類的時候,父類還沒有初始化,會事先初始化父類;
  • 啟動虛擬機器時,需要初始化包含main方法的類;
  • 訪問某個類或介面的靜態變數,或者對該靜態變數賦值;

2.定義物件陣列,不會觸發該類的初始化。