1. 程式人生 > >JVM載入class檔案的原理機制

JVM載入class檔案的原理機制

Java語言是一種具有動態性的解釋型語言,類(class)只有被載入到JVM中後才能執行。當執行指定程式時,JVM會將編譯生成的.class檔案按照需求和一定的規則載入到記憶體中,並組織成為一個完整的Java應用程式。這個載入過程是由類載入器來完成的,具體來說,就是由ClassLoader和它的子類來實現的。類載入器本身也是一個類,其實質是把類檔案從硬碟讀取到記憶體中

類的載入方式分為隱式載入與顯式載入兩種。隱式載入指的是程式在使用new等方法建立物件時,會隱式地呼叫類的載入器把對應的類載入到JVM中。顯式載入指的是通過直接呼叫class.forName()方法來把所需要的類載入到JVM中。

在寫程式的時候,我們幾乎不需要關心類的載入,因為這些都是隱式裝載的,除非我們有特殊的用法,像是反射,就需要顯式的載入所需要的類。

(任何一個工程專案都是由許多個類組成的,當程式啟動時,只把需要載入的類載入到JVM中,其他類只有被使用到的時候才會被載入,採用這種方法,一方面可以加快載入速度,另外一方面可以節約程式執行過程中對記憶體的開銷。此外,在Java語言中,每個類或介面都對應一個.class檔案,這些檔案可以被看成一個個可以被動態載入的單元,因此當只有部分類被修改時,只需要重新編譯變化的類即可,而不需要重新編譯所有檔案,因此加快了編譯速度。)

在Java語言中,類的載入是動態的,它並不會一次性將所有的類全部載入後再執行,而是保證程式執行的基礎類(例如基類)完全載入到JVM中,至於其他類,則在需要時才載入,節省了記憶體開銷。

在Java語言中,可以把類分為3類:系統類、擴充套件類和自定義類。Java針對這3種不同的類提供了3中型別的載入器,這3種載入器的關係如下:Java的類載入器有三個,對應Java的三種類:

     Bootstrap Loader  // 負責載入系統類 (指的是內建類,像是String,對應於C#中的System類和C/C++標準庫中的類)             |           - - ExtClassLoader   // 負責載入擴充套件類(就是繼承類和實現類)                           |                       - - AppClassLoader   // 負責載入應用類(程式設計師自定義的類)

以上這三個類是如何協調工作來完成類的載入呢?

其實,它們是通過委託的方式實現的。具體而言,就是當有類需要被載入時,類載入器會請求父類來完成這個載入工作,父類會使用其自己的搜尋路徑來搜尋需要被載入的類,如果搜尋不到,才會由子類按照其搜尋路徑來搜尋待載入的類。下例可以充分說明類載入器的工作原理:

package com.js;
/**
 * 說明類載入器的工作原理
 * @author jiangshuai
 *
 */
public class TestLoader {
	public static void main(String[] args){
		//呼叫Class載入器
		ClassLoader clApp = TestLoader.class.getClassLoader();
		System.out.println(clApp);
		//呼叫上一層Class載入器
		ClassLoader clExt = clApp.getParent();
		System.out.println(clExt);
		//呼叫根部Class載入器
		ClassLoader clBoot = clExt.getParent();
		System.out.println(clBoot);
	}
}

執行結果:

[email protected]

[email protected]

null

從上例可以看出,TestLoader類是由AppClassLoader來載入的。另外需要說明的一點是,由於Bootstrap Loader是用C++語言來實現的,因此,在Java語言中是看不到它的,所以此時程式會輸出null。

類載入的主要步驟分為以下3步:

1.裝載:查詢和匯入class檔案;

2.連線:

      (1)檢查:檢查載入的class檔案資料的正確性;

      (2)準備:為類的靜態變數分配儲存空間;

      (3)解析:將符號引用轉換成直接引用(這一步是可選的)

3.初始化:初始化靜態變數,靜態程式碼塊。

      這樣的過程在程式呼叫類的靜態成員的時候開始執行,所以靜態方法main()才會成為一般程式的入口方法。類的構造器也會引發該動作。