1. 程式人生 > >Java之類載入器(Class Loader)

Java之類載入器(Class Loader)

JVM預設有三個類載入器:

  • Bootstrap Loader

    Bootstrap Loader通常有C編寫,貼近底層作業系統。是JVM啟動後,第一個建立的類載入器。

  • Extended Loader

    Extended Loader由Java編寫,由Bootstrap Loader建立。JVM啟動後,第二個被建立的類載入器。在Oracle JDK中,對應sum.misc.Launcher$ExtClassLoader($表示內部類)。

  • System Loader

    System Loader由Java編寫,同樣由Bootstrap Loader建立

    。JVM啟動後,第三給被建立的類載入器。在Oracle JDK中,對應sum.misc.Launcher$AppClassLoader

       

JVM啟動後,類載入器的建立順序如下:

  1. JVM建立Bootstrap Loader;
  2. 由Bootstrap Loader建立Extended Loader;
  3. 設定Bootstrap Loader為Extended Loader的父類
  4. 用Bootstrap Loader建立System Loader;
  5. 設定Extended Loader為System Loader的父類

如下圖:

從建立過程可見,類載入器間是有層級關係的

當類載入器有載入任務時,會先把載入任務交給父載入器,如果父載入器無法載入,才由自己載入。所以載入類的時候,會以Bootstrap Loader → Extended Loader → System Loader的載入類。如果所有載入器載入類失敗,丟擲java.lang.NoClassDefFoundError異常。

每個類載入器,會到其指定的目錄下,根據類名載入類檔案。三個預設類載入器的指定目錄保持在JVM的系統屬性裡。

Bootstrap Loader

sun.boot.class.path

可以在編譯時期,使用-bootclasspath

指定。

Extended Loader

java.ext.dirs

System Loader

java.class.path

可以在執行程式時,使用-cp指令覆蓋CLASSPATH系統環境變數。

可以使用System.getProperty()方法獲取實際值。

   

三個預設類載入器在程式啟動後,就無法更改它們的搜尋目錄。如果在程式執行過程中,打算動態載入其他路徑下的類,可以建立java.net.URLClassLoader例項,使用新的類載入器。

URLClassLoader類建立例項時,需要java.net.URL陣列作為引數指定新的類載入搜尋路徑。

ClassLoader loader = new URLClassLoader(new URL[] {new URL(pathA), new URL(pathB)});

loader.loadClass(clzName);

URLClassLoader類的例項,將由Bootstrap Loader建立,指定父載入器為System Loader

由於使用URL協議,可以指定遠端伺服器上的類檔案,使用本地路徑時,注意新增字首"file:/"

   

類載入器可以使用loadClass()方法載入類,預設不會執行類的靜態初始區塊。但會在第一次新建該類例項的時候執行靜態初始區塊

可以使用getParent()獲取類載入器的父載入器。自定義物件預設用System Loader載入,可以使用Class.getClassLoader()獲取載入該類的類載入器。

// 獲取System Loader

ClassLoader sysClassLoader = Empty.class.getClassLoader();

// 獲取Extended Loader

ClassLoader extClassLoader = sysClassLoader.getParent();

// 獲取Bootstrap Loader

ClassLoader bootClassLoader = extClassLoader.getParent();

   

System.out.println(sysClassLoader);

System.out.println(extClassLoader);

System.out.println(bootClassLoader);

輸入如下:

[email protected]

[email protected]

null

獲取Extended Loader的父載入器時,返回值為null,但並不代表它沒父載入器。因為Bootstrap Loader通常由C實現,在Java中沒實際類例項來表示,所有會顯示null

標準API的類(包括陣列物件,包裝器),都是由Bootstrap Loader載入的。

// 以下均輸出null

System.out.println(String.class.getClassLoader());

System.out.println(int[].class.getClassLoader());

System.out.println(Integer.class.getClassLoader());

System.out.println(Class.class.getClassLoader());

   

同一個類檔案,由同一個類載入器(實際載入的那個類載入器,注意載入任務會先向父載入器傳遞)多次載入,只有一個Class例項;如果由不同的類載入器載入,會由不同的Class例項。

參考資料:《Java學習筆記》 第17章