流程
首先類加載在整個體系結(jié)構(gòu)的哪一個環(huán)節(jié)呢?見紅色圈住的部分。
類加載器分為那幾個過程呢?五個過程
加載
根據(jù)類的全限定名(簡單理解為類的絕對路徑,見附錄),找到指定的字節(jié)碼文件,并在內(nèi)存中生產(chǎn)一個java.lang.Class的對象,存放在方法區(qū)中。
驗證
作用:確保字節(jié)碼文件中包含的信息符合Class文件格式規(guī)范,對虛擬機(jī)來說是安全的。
規(guī)則一直在更新,大體有四種
1. 文件格式驗證 基于二進(jìn)制字節(jié)流進(jìn)行分析。
2. 元數(shù)據(jù)驗證(可以理解成是對類層面的信息驗證) 對類的元數(shù)據(jù)進(jìn)行語義分析。
3. 字節(jié)碼驗證(對方法層面的信息驗證)* 對方法體語義分析。
4. 符號引用驗證 驗證根據(jù)引用能否找到對應(yīng)的類、方法、字段。
如果確認(rèn)字節(jié)碼文件是安全的,通過 -Xverify:none 關(guān)閉大部分驗證。
準(zhǔn)備
在方法區(qū)中為類的靜態(tài)變量分配內(nèi)存并初始化。
解析
將常量池中的符號引用替換為直接引用的過程。
初始化
執(zhí)行類構(gòu)造器<client>方法,<client>方法是由編譯器自動收集的類中的類變量賦值操作和靜態(tài)語句塊中的語句。并且會保證父類的<client>方法先執(zhí)行。
加載過程由誰來執(zhí)行的
類加載器 classLoader,也就是 Java.lang.ClassLoader。核心函數(shù)是loadClass
protected synchronized Class<?> loadClass (String name,boolean resolve) throws ClassNotFoundException {
// 首先檢查類是不是已經(jīng)被加載
Class c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
//如果父類不為空,優(yōu)先檢查父類的
c = parent.loadClass(name, false);
} else { //否則檢查當(dāng)前的
c = findBootstrapClass0(name);
}
} catch (ClassNotFoundException e) { // 如果還是找不到,就觸發(fā)子類本身的findClass方法去找
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
類加載器
兩大類,四小種:JDK默認(rèn)提供的三種,用戶自定義的一種。
默認(rèn)的三種有(非繼承關(guān)系)
-
Bootstrap ClassLoader 啟動類加載器,沒有父類。
- 一般是native code(C++)實現(xiàn)
- 用于加載虛擬機(jī)的核心類(<JAVA_HOME>/jre/lib/rt.jar),包括擴(kuò)展類/系統(tǒng)類加載器
-
Extension ClassLoader 擴(kuò)展類加載器,父類加載器為空
- java實現(xiàn),是rt.jar中sun.misc.Launcher的內(nèi)部類sun.misc.Launcher$ExtClassLoader (miscellaneous)
- 用于加載擴(kuò)展庫中的類(<JAVA_HOME>/jre/lib/ext)
-
System ClassLoder 父類加載器Ext ClassLoader
- java實現(xiàn),是rt.jar中sun.misc.Launcher的內(nèi)部類sun.misc.Launcher$AppClassLoader
- 用于CLASS_PATH中的類
用戶自定義的有一種 父類是 System ClassLoader
- 繼承自java.lang.ClassLoader
同名文件處理
這里有一個雙親委派的概念。就是當(dāng)查找一個類的時候,會一層一層的向上委托查詢,如果父類加載器有對應(yīng)的類,就直接從父類加載該類。
這樣的雙親委派有好處,但是有些場景我們是希望破壞雙親委派的
-
場景一:我們想在頂層的classLoader中加載底層的classLoader
- 可以在線程中放入底層的classLoader到Thread.setContextClassLoader()中,然后在頂層的classLoader中使用Thread.getContextClassLoader()加載第三方的classLoader實現(xiàn)。
-
場景二:實現(xiàn)類熱部署
- 一個class只能被一個classLoader加載一次,當(dāng)需要實現(xiàn)代碼熱部署的時候可以每次都new一個自定義的classLoader來加載新的Class文件。
場景三:Tomcat中使用WebAppClassLoader進(jìn)行單獨加載,加載不了再去委托父加載器去加載。