注:這是自己在復習java基礎(chǔ)知識的時候伏伐,從書本和網(wǎng)絡當中整理出來的帕翻,目前還不是很完善鸠补,歡迎大家補充和討論,謝謝嘀掸。
1. 類加載器(class loader)是用來加載java類到java虛擬機中紫岩,是JVM實現(xiàn)的一部分。與C和C++不同睬塌,java程序并不是一個可執(zhí)行文件泉蝌,而是由許多獨立的類文件組成的,每一個文件對應一個java類揩晴。此外勋陪,這些類文件并非全部裝入內(nèi)存,而是根據(jù)程序需要逐漸載入硫兰,所以就有ClassLoader產(chǎn)生诅愚。
2. 類記載器大致可以分為兩類:系統(tǒng)提供+由java應用開發(fā)人員編寫。系統(tǒng)提供主要有下面三種:
(1),bootstrap classloader劫映,也叫啟動類加載器违孝,是用C++語言寫的,是虛擬機自身的一部分泳赋。它是在Java虛擬機啟動后初始化的雌桑,它用來加載java核心的API,以滿足java程序最基本的需求摹蘑,是用原生代碼實現(xiàn)的筹燕,并不繼承自java.lang.ClassLoader。其中就包括要加載用戶自定義的ClassLoader。
(2),ExtClassLoader撒踪,擴展類加載器过咬,Bootstrap loader加載ExtClassLoader,并且將ExtClassLoader的父加載器設置為Bootstrp loader。該加載器使用java寫的制妄,它用來加載java的擴展庫掸绞,java虛擬機的實現(xiàn)會提供一個擴展庫目錄,該類加載器在此目錄里面查找并加載java類耕捞。
(3),AppClassLoader衔掸,Bootstrp loader加載完ExtClassLoader后,就會加載AppClassLoader,并且將AppClassLoader的父加載器指定為 ExtClassLoader俺抽。它也是用java寫的敞映,它根據(jù)java應用的類路徑(CLASSPATH)來加載類。一般來說磷斧,java應用的類都是由它來完成加載的振愿。通常,在沒有指定ClassLoader的情況下弛饭,程序員自定義的類就由該ClassLoader加載冕末。ClassLoader中有個getSystemClassLoader方法,此方法返回的正是AppclassLoader.
3.加載流程:JVM啟動時,運行bootstrap classloader侣颂,該ClassLoader加載java核心API(ExtClassLoader和AppClassLoader也在此時被加載)档桃,然后調(diào)用ExtClassLoader加載擴展API,最后AppClassLoader加載CLASSPATH目錄下定義的Class憔晒,這就是一個程序最基本的加載流程藻肄。
4.加載時的父類委托模式:
(1)當前ClassLoader首先從自己已經(jīng)加載的類中查詢是否此類已經(jīng)加載,如果已經(jīng)加載則直接返回原來已經(jīng)加載的類拒担。
(2)當前classLoader的緩存中沒有找到被加載的類的時候仅炊,委托父類加載器去加載,父類加載器采用同樣的策略澎蛛,首先查看自己的緩存,然后委托父類的父類去加載蜕窿,一直到bootstrap ClassLoader.
(3)當所有的父類加載器都沒有加載的時候谋逻,再由當前的類加載器加載,并將其放入它自己的緩存中桐经,以便下次有加載請求的時候直接返回毁兆。
偽代碼:
//首先檢查該name指定的class是否被加載
Class c = findLoaderClass(name);
//如果該類沒有被加載,則調(diào)用父類加載器進行加載
if(c==null)
if(parent != null)
c= parent.loadClass(name,false);
//如果parent為null阴挣,則調(diào)用boottrapClassLoader進行加載
c = findBootstrapClass(name)
//如果仍然無法加載气堕,則調(diào)用自身的findClass進行加載
c = findClass(name);
這樣做的目的第一是可以避免重復加載,當父類已經(jīng)加載該類的時候,子類就沒必要再加載一次茎芭。第二就是考慮到安全因素揖膜,如果不使用這種模式,那么可以隨時使用自定義的String來動態(tài)替代Java核心API中定義的類型梅桩,這樣會存在非常大的安全隱患壹粟,而父類委托模式就可以避免這種情況,因為String已經(jīng)在啟動時被加載宿百,所以用戶自定義類是無法加載一個自定義的ClassLoader趁仙。
還有另外一種說法,引用別人的話:
Java為什么要采用這樣的委托機制垦页?理解這個問題雀费,我們引入另外一個關(guān)于Classloader的概念“命名空間”, 它是指要確定某一個類痊焊,需要類的全限定名以及加載此類的ClassLoader來共同確定盏袄。也就是說即使兩個類的全限定名是相同的,但是因為不同的 ClassLoader加載了此類宋光,那么在JVM中它是不同的類貌矿。明白了命名空間以后,我們再來看看委托模型罪佳。采用了委托模型以后加大了不同的 ClassLoader的交互能力逛漫,比如上面說的,我們JDK本生提供的類庫赘艳,比如hashmap,linkedlist等等酌毡,這些類由bootstrp 類加載器加載了以后,無論你程序中有多少個類加載器蕾管,那么這些類其實都是可以共享的枷踏,這樣就避免了不同的類加載器加載了同樣名字的不同類以后造成混亂。
5.自己實現(xiàn)ClassLoader
在絕大多數(shù)情況下系統(tǒng)默認提供的類加載器實現(xiàn)已經(jīng)可以滿足需求掰曾。但是在某些情況下旭蠕,還是需要為應用開發(fā)出自己的類加載器。比如您的應用通過網(wǎng)絡來傳輸 Java 類的字節(jié)代碼旷坦,為了保證安全性掏熬,這些字節(jié)碼經(jīng)過了加密處理。這個時候您就需要自己的類加載器來從某個網(wǎng)絡地址上讀取加密后的字節(jié)代碼秒梅,接著進行解密和驗證旗芬,最后定義出要在 Java 虛擬機中運行的類來。