個人學習整理,如有不足之處,請不吝指教。轉載請注明:
類加載器(class loader)用來加載 Java 類到 Java 虛拟機中。一般來說,Java 虛拟機使用 Java 類的方式如下:Java 源程式(.java 檔案)在經過 Java 編譯器編譯之後就被轉換成 Java 位元組代碼(.class 檔案)。類加載器負責讀取 Java 位元組代碼,并轉換成 java.lang.Class類的一個執行個體。每個這樣的執行個體用來表示一個
Java 類。通過此執行個體的 newInstance()方法就可以建立出該類的一個對象。實際的情況可能更加複雜,比如 Java 位元組代碼可能是通過工具動态生成的,也可能是通過網絡下載下傳的。
Java 中的類加載器的分類如下圖,看圖簡潔明了:
啟動類加載器(bootstrap class loader):加載 Java 的核心庫。比如位于<JAVA_HOME>/jre/lib 目錄下的vm.jar,core.jar。
擴充類加載器(extensions class loader):加載 Java 的擴充庫。一般位于<JAVA_HOME>/jre/lib/ext 或者通過java.ext.dirs 這個系統屬性指定的路徑下的代碼。這個類加載器是由sun.misc.Launcher$ExtClassLoader
實作的。
系統類加載器(system class loader):根據 Java 應用的類路徑(CLASSPATH)來加載
Java 類。加載java.class.path(映射系統參數 CLASSPATH的值) 路徑下面的代碼,這個類加載器是由 sun.misc.Launcher$AppClassLoader 實作的。
除了啟動類加載器,所有的類加載器對象都有一個可以作為其雙親的類加載器對象。
通過 ClassLoader 類的 getParent 方法可以擷取雙親類加載器對象。
我們自定義的類加載器 Java 類繼承自 ClassLoader 類,而 ClassLoader 類的構造方法中可以指定類加載器的雙親類加載器對象,是以我們可以在自定義的類加載器的構造方法中調用父類 ClassLoader
類的構造方法,指定雙親類加載器對象的值。
若我們在自定義類加載器時沒有指定雙親類加載器,則預設的雙親類加載器是系統類加載器。
若目前類加載器對象的雙親類加載器是啟動類加載器,則其 getParent 方法傳回 null。
下面是測試代碼:
測試結果:
sun.misc.Launcher$AppClassLoader@4d77c977 ---> 預設為系統類加載器
sun.misc.Launcher$ExtClassLoader@734bcb5c
---> getParent方法得到擴充類加載器
---> getParent方法傳回null
通過以上的簡單代碼和輸出結果可以很好的說明我們上面的說法。
根據以上的分析,我們可以發現這種加載的過程形成了一種層次結構,這種層次結構可以用如下簡圖表示:
沒有自己定義的類加載器時 有自己定義的類加載器時
一般應用程式都是由以上三種基本的類加載器加載的,當然,有時候也會使用我們自定義的類加載器。這些類加載器構成了一種層次結構,稱為類加載器的雙親委派模型。
所有的類加載器(除了啟動類加載器)對象都有一個可以作為其雙親的類加載器對象,通過組合關系來複用雙親類加載器的方法。
當一個類加載器收到類加載請求時,它并不會第一時間自己去加載這個類,而是把該請求委派給雙親類加載器去完成,每個層次的類加載器都是如此(雙親類加載器再将請求委派給它的雙親類加載器),如果雙親類加載器可以完成類加載任務,就成功傳回;隻有當雙親類加載器無法完成該加載請求時(它的搜尋範圍内沒有找到所需要的類),子類加載器才會自己去加載。(此處可以通俗的了解為遞歸)
關于虛拟機中預設的雙親委派機制,我們可以檢視 java.lang.ClassLoader 類的 loadClass
方法,源碼及分析如下:
最近在看 java 虛拟機這一塊,将自己的一些學習心得記錄下來,分享給大家,多多指教。
***************************************************************************
* 轉載請注明出處:
*
***************************************************************************