類加載包含兩部分:一部分是被誰加載季蚂,另一部分是如何加載。
被誰加載是指 ClassLoader 的雙親委派模型,如何加載是指類的加載過程刽肠。
這篇博客介紹雙親委派模型,特別感謝 @書呆子Rico老師 的博客
ClassLoader 結(jié)構(gòu)核心思想
class ClassLoader {
/**
* 父加載器
*/
ClassLoader parent;
/**
* 已經(jīng)加載的 class
* 這個(gè)屬性是我假想的免胃,為了配合 {@link #findLoadedClass} 的猜想
*/
Map<String, Class> loadedClasses;
/**
* 嘗試從已經(jīng)加載的類中尋找音五,如果沒有返回 null
* 真實(shí)的實(shí)現(xiàn)是 native 方法,我猜想是存了一個(gè)類名到類實(shí)例的映射羔沙,如下
*/
Class<?> findLoadedClass(String name){
return loadedClasses.get(name);
}
/**
* 當(dāng)前類加載器嘗試去加載一個(gè)類躺涝,內(nèi)部實(shí)現(xiàn)就是類的加載過程
* 為什么說嘗試?因?yàn)楫?dāng)前類加載器可能無法加載這個(gè)類扼雏,會(huì)返回 null
*/
Class<?> findClass(String name){}
/**
* 雙親委派模型的實(shí)現(xiàn)坚嗜,也是類加載的直接入口
*/
Class<?> loadClass(String name){}
}
雙親委派模型
當(dāng)類加載器嘗試加載一個(gè)類時(shí),會(huì)首先查看自己加載過的類诗充。如果沒有查找到苍蔬,不是馬上去加載,而是去詢問父加載器(這是一個(gè)遞歸的過程)蝴蜓。如果父加載器也沒有加載碟绑,自己才會(huì)加載俺猿。雙親委派模型是通過組合的方式實(shí)現(xiàn)的,不是繼承格仲。
雙親委派實(shí)現(xiàn)自己實(shí)現(xiàn)的偽代碼
Class<?> loadClass(String name) {
// 查找自己加載過的類
Class<?> loadedClass = findLoadedClass(name);
if (loadedClass == null) {
// 嘗試讓父類加載
if (parent == null) {
// 調(diào)用 BootstrapClassLoader 去加載押袍,后面介紹 Java 類加載器的層級(jí)結(jié)構(gòu)
} else {
loadedClass = parent.loadClass(name);
}
// 如果父類沒有加載,自己加載
if (loadedClass == null) {
loadedClass = findClass(name);
}
}
// 返回最終結(jié)果抓狭,此時(shí)還有可能為 null
// 如果當(dāng)前類加載器有子加載器伯病,則子加載器還會(huì)嘗試加載,否則就會(huì)包 ClassNotFoundException
return loadedClass;
}
雙親委派作用
- 防止類重復(fù)加載提高效率
- 保證核心類安全否过,無法被替換
假設(shè)通過網(wǎng)絡(luò)傳遞一個(gè)名為java.lang.Integer
的類午笛,通過雙親委托模式傳遞到啟動(dòng)類加載器,而啟動(dòng)類加載器在核心Java API發(fā)現(xiàn)這個(gè)名字的類苗桂,發(fā)現(xiàn)該類已被加載药磺,并不會(huì)重新加載網(wǎng)絡(luò)傳遞的過來的類,而直接返回已加載過的Integer.class
煤伟,這樣便可以防止核心API庫被隨意篡改癌佩。
Java 類加載器層級(jí)結(jié)構(gòu)
如雙親委派模型圖中展示的,Java 中現(xiàn)有類加載器分三層便锨。
-
BootstrapClassLoader
围辙,啟動(dòng)類加載器,頂級(jí)類加載器放案,由 native 實(shí)現(xiàn)姚建,加載JAVA_HOME/lib下面的核心類庫或-Xbootclasspath選項(xiàng)指定的jar包等虛擬機(jī)識(shí)別的類
。 -
ExtClassLoader
吱殉,拓展類加載器掸冤,父加載器是BootstrapClassLoader
,所以parent==null
友雳,加載JAVA_HOME /lib/ext或者由系統(tǒng)變量-Djava.ext.dir指定位置中的類
稿湿。 -
AppClassLoader
,系統(tǒng)類加載器押赊,默認(rèn)的類加載器饺藤,也是自定義類加載器的父加載器,加載當(dāng)前類所在路徑及其引用的第三方類流礁。