目錄
- 一、回顧一下類加載程序
- 二、類加載器總結
- 三、雙親委派模型
- 1.雙親委派模型介紹
- 2.雙親委派模型實作原始碼分析
- 3.雙親委派模型的好處
- 4.如果我們不想用雙親委派模型怎么辦?
- 四、自定義類加載器
一、回顧一下類加載程序
類加載程序:加載->連接->初始化,連接程序又可分為三步:驗證->準備->決議,

一個非陣列類的加載階段(加載階段獲取類的二進制位元組流的動作)是可控性最強的階段,這一步我們可以去完成還可以自定義類加載器去控制位元組流的獲取方式(重寫一個類加載器的 loadClass() 方法),陣列型別不通過類加載器創建,它由 Java 虛擬機直接創建,
所有的類都由類加載器加載,加載的作用就是將 .class檔案加載到記憶體,
二、類加載器總結
JVM 中內置了三個重要的 ClassLoader,除了BootstrapClassLoader其他類加載器均由 Java 實作且全部繼承自java.lang.ClassLoader :
- BootstrapClassLoader(啟動類加載器) :最頂層的加載類,由C++實作,負責加載
%JAVA_HOME%/lib目錄下的jar包和類或者或被-Xbootclasspath引數指定的路徑中的所有類, - ExtensionClassLoader(擴展類加載器) :主要負責加載目錄
%JRE_HOME%/lib/ext目錄下的jar包和類,或被java.ext.dirs系統變數所指定的路徑下的jar包, - AppClassLoader(應用程式類加載器) :面向我們用戶的加載器,負責加載當前應用classpath下的所有jar包和類,
參考資料:《Java中高級核心知識全面決議》
有想要獲取這份學習資料的同學可以點擊這里免費獲取
三、雙親委派模型
1.雙親委派模型介紹
每一個類都有一個對應它的類加載器,系統中的ClassLoder在協同作業的時候會默認使用雙親委派模型,即在類加載的時候,系統會首先判斷當前類是否被加載過,已經被加載的類會直接回傳,否則才會嘗試加載,加載的時候,首先會把該請求委派該父類加載器的loadClass()處理,因此所有的請求最終都應該傳送到頂層的啟動類加載器BootstrapClassLoader中,當父類加載器無法處理時,才由自己來處理,當父類加載器為null時,會使用啟動類加載器BootstrapClassLoader作為父類加載器,

每個類加載都有一個父類加載器,我們通過下面的程式來驗證,
public class ClassLoaderDemo {
public static void main(String[] args) {
System.out.println("ClassLodarDemo's ClassLoader is " +
ClassLoaderDemo.class.getClassLoader());
System.out.println("The Parent of ClassLodarDemo's ClassLoader is " +
ClassLoaderDemo.class.getClassLoader().getParent());
System.out.println("The GrandParent of ClassLodarDemo's ClassLoader is " +
ClassLoaderDemo.class.getClassLoader().getParent().getParent());
}
}
Output
ClassLodarDemo's ClassLoader is sun.misc.Launcher$AppClassLoader@18b4aac2
The Parent of ClassLodarDemo's ClassLoader is
sun.misc.Launcher$ExtClassLoader@1b6d3586
The GrandParent of ClassLodarDemo's ClassLoader is null
AppClassLoader 的父類加載器為 ExtClassLoader
ExtClassLoader 的父類加載器為null,null并不代表ExtClassLoader 沒有父類加載器,而是BootstrapClassLoader ,
其實這個雙親翻譯的容易讓別人誤解,我們一般理解的雙親都是父母,這里的雙親更多地表達的是“父母這一輩”的人而已,并不是說真的有一個 Mother ClassLoader 和一個 Father ClassLoader ,另外,類加載器之間的“父子”關系也不是通過繼承來體現的,是由“優先級”來決定,官方API檔案對這部分的描述如下:
The Java platform uses a delegation model for loading classes. The basic idea is that everyclass loader has a “parent” class loader. When loading a class, a class loader first"delegates" the search for the class to its parent class loader before attempting to find theclass itself.
2.雙親委派模型實作原始碼分析
雙親委派模型的實作代碼非常簡單,邏輯非常清晰,都集中在java.lang.ClassLoader的loadClass()中,相關代碼如下所示,
private final ClassLoader parent;
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 首先,檢查請求的類是否已經被加載過
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {//父加載器不為空,呼叫父加載器loadClass()方法處理
c = parent.loadClass(name, false);
} else {//父加載器為空,使用啟動類加載器 BootstrapClassLoader加載
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
//拋出例外說明父類加載器無法完成加載請求
}
if (c == null) {
long t1 = System.nanoTime();
//自己嘗試加載
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}return c;
}
}
3.雙親委派模型的好處
雙親委派模型保證了Java程式的穩定運行,可以避免類的重復加載(JVM 區分不同類的方式不僅僅根據類名,相同的類檔案被不同的類加載器加載產生的是兩個不同的類),也保證了 Java 的核心 API 不被篡改,如果沒有使用雙親委派模型,而是每個類加載器加載自己的話就會出現一些問題,比如我們撰寫一個稱為 java.lang.Object 類的話,那么程式運行的時候,系統就會出現多個不同的 Object 類,
4.如果我們不想用雙親委派模型怎么辦?
為了避免雙親委托機制,我們可以自己定義一個類加載器,然后重寫 loadClass() 即可,
四、自定義類加載器
除了BootstrapClassLoader其他類加載器均由 Java 實作且全部繼承自java.lang.ClassLoader,如果我們要自定義自己的類加載器,很明顯需要繼承ClassLoader,
參考資料:《Java中高級核心知識全面決議》
有想要獲取這份學習資料的同學可以點擊這里免費獲取
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/236069.html
標籤:java
上一篇:WEB專案jsp使用Java Bean&Eclipse的WEB-INF目錄下 沒有/不顯示 classes檔案夾的問題解決
