寫在前面
本文主要介紹了四種類加載器,以及算清委託機制。文章可能還有很多不足,請大家諒解,歡迎大佬提意見。
本文使用到的東西
- java
1.類加載器
1.1 類加載器作用:
類加載器負責從文件或者網絡中加載Class信息,加載的類信息存放於方法區的內存空間。
1.2 啓動類加載器(BootStrap ClassLoader):
- C++實現,是虛擬機的一部分;
- 負責加載“
%JAVA_HOME%\lib
”目錄中,或者-Xbootclasspath
參數指定路徑中的類庫到虛擬機; - 無法被java程序直接引用。
1.3 擴展類加載器(Extension ClassLoader):
獨立於JVM,由sun.misc.Launcher$ExtClassLoader實現,加載”%JAVA_HOME%\lib\ext
”目錄中,或者java.ext.dirs
系統變量指定的路徑中的所有類庫,該類加載器無法被java程序直接引用。
1.4 應用程序類加載器(Application ClassLoader):
獨立於JVM,由sun.misc.Launcher$AppClassLoader
實現,也叫系統類加載器。負責加載用戶類路徑(classpath)上指定的類庫,可以直接使用,一般情況下是默認的類加載器。
1.5 啓動類加載器(BootStrap ClassLoader):
獨立於JVM,需要繼承於java.lang.ClassLoader
抽象類,複寫Class<?> findClass(String name)
方法。讀取類文件的二進制數據流,通過Class<?> defineClass
方法加載類。
2.雙親委託機制
在加載類時必須先交給父加載器加載,父加載器不存在則交給啓動類加載器加載,還沒加載到再自己加載;目的是爲了避免類的重複加載。
已知java中類加載器都繼承於java.lang.ClassLoader
抽象類,通過loadClass(String name)
方法加載類:
loadClass(String name):
//加載類的方法
public Class<?> loadClass(String name) throws ClassNotFoundException {
//調用了loadClass(name, resolve)方法,false表示不解析類
return loadClass(name, false);
}
loadClass(name, resolve):
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 檢查類是否已經加載
Class<?> c = findLoadedClass(name);
// 未加載情況
if (c == null) {
long t0 = System.nanoTime();
try {
/**
* 雙親委託
* 判斷父類加載器是否存在,存在則交給父類加載器加載
* 不存在父加載器則交給啓動類加載器(BootStrap ClassLoader)加載
*/
if (parent != null) {
// 父類加載器加載
c = parent.loadClass(name, false);
} else {
// 啓動類加載器加載
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
long t1 = System.nanoTime();
// 如果還沒有加載到類,則交給findClass(name)來加載
c = findClass(name);
// this is the defining class loader; record the stats
PerfCounter.getParentDelegationTime().addTime(t1 - t0);
PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
// 解析類
resolveClass(c);
}
return c;
}
}
// 自定義類時交給我們來複寫
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
通過閱讀源碼我們可以知道,我們只需要繼承ClassLoader抽象類,複寫findClass(String name)即可實現自定義類加載器。而複寫loadClass(String name, boolean resolve)
方法則可以破壞雙親委託機制。
3.總結
本文簡單描述了JVM的類加載器以及雙親委託,從ClassLoader源碼層面分析了類加載機制。有不清楚的地方歡迎評論留言,看到的我都會回覆的。本文到此結束,有什麼不足的地方請大家不吝指正。