學(xué)習(xí)筆記:深入分析ClassLoader工作機(jī)制

深入分析ClassLoader工作機(jī)制

ClassLoader除了能將Class加載到JVM中之外,還有一個重要的作用就是審查每個類應(yīng)該由誰加載急迂,它是一種父優(yōu)先的等級加載機(jī)制。

Classloader類結(jié)構(gòu)分析

我們常會用到或擴(kuò)展ClassLoader,主要會用到如下幾個方法:

ClassLoader
defineClass(byte[],int,int)
findClass(String)
leadClass(String)
resolveClass(Class<?>)

其中defineClass方法用來將byte字節(jié)流解析成JVM能夠是別的Class對象,有了這個方法意味著我們不僅僅可以通過class文件實例化對象慕购,還可以通過其他方式實例化對象,如我們通過網(wǎng)絡(luò)接收到一個類的字節(jié)碼茬底,拿這個字節(jié)碼流直接創(chuàng)建類的實例化對象沪悲。注意,如果直接調(diào)用這個方法生成類的Class對象桩警,這個類的Class對象還沒有resolve可训,這個resolve將會在這個對象真正實例化時才進(jìn)行昌妹。

defineClass通常是和findClass方法一起使用的捶枢,我們通過直接覆蓋ClassLoader父類的findClass方法來實現(xiàn)類的加載規(guī)則,從而取得要加載類的字節(jié)碼飞崖。然后調(diào)用defineClass方法生成類的Class對象烂叔,如果你想在類被加載到JVM中時就被鏈接(Link),那么可以接著調(diào)用另外一個resolveClass方法固歪,當(dāng)然你也可以選擇讓JVM來解決什么時候才鏈接這個類蒜鸡。

如果你不想重新定義加載類的規(guī)則,也沒有復(fù)雜的處理邏輯牢裳,只想在運(yùn)行時能夠加載自己指定的一個類逢防,那么你可以用this.getClass().getClassLoader().loadClass("class")調(diào)用ClassLoader的loadClass方法以獲取這個類的Class對象,這個loadClass還有重載方法蒲讯,你同樣可以決定在什么時候解析這個類忘朝。

ClassLoader是個抽象類,它還有很多子類判帮,我們?nèi)绻獙崿F(xiàn)自己的ClassLoader局嘁,一般都會繼承URLClassLoader這個子類溉箕,因為這個類已經(jīng)幫我們實現(xiàn)了大部分工作,我們只需要在適當(dāng)?shù)牡胤阶鲂┬薷木托小?/p>

ClassLoader的等級加載機(jī)制(上級委托接待機(jī)制)

如何保證不同等級的會員通過不同的會員接待室進(jìn)入會場悦昵?保證每個會員不會走錯接待室肴茄,并且每個會員只能被一個接待室接待,從而保持接待的一致性但指。如何設(shè)計這個接待規(guī)則寡痰?

ClassLoader就設(shè)計了這樣一種接待機(jī)制,就是上級委托接待機(jī)制棋凳。具體是這樣的:任何一個會員到達(dá)任何一個接待室時氓癌,這個接待室首先會檢查這個會員是否已經(jīng)被自己接待過,如果接待過贫橙,那么拒絕本次接待贪婉,也就是不再發(fā)入會證明了,如果沒有接待過卢肃,那么會向上詢問這個會員是否應(yīng)該在上一級的更高級別的接待室接待疲迂,上級接待室會根據(jù)它們的接待規(guī)則,檢查這個會員是否已經(jīng)被接待過莫湘,如果已經(jīng)接待過尤蒿,同樣的處理方式,將已經(jīng)接待過的結(jié)果反饋給下一級幅垮,如果也沒有接待過腰池,再向更高一級接待室轉(zhuǎn)發(fā)接待請求,更高一級也還是同樣的處理方法忙芒,直到有一級接待室接待或者告訴它下一級這個會員不是自己接待的這個結(jié)果示弓;如果這個會員來到的這個接待室得到它上一級的接待室反饋認(rèn)為這個會員沒有被接待,并且也不應(yīng)該有它們接待呵萨,這個接待室會正式接待這個會員奏属,并發(fā)給他入會證明,這個會員就會被定義為這個接待室等級的會員潮峦。

整個JVM平臺提供三層ClassLoader囱皿,這三層ClassLoader可以分為兩種類型,可以理解為--->為接待室服務(wù)的接待室和為會員服務(wù)的接待室兩種忱嘹。

(1)Bootstrap ClassLoader嘱腥,這個ClassLoader就是接待室服務(wù)自身的,它主要加載JVM自身工作需要的類拘悦。這個ClassLoader完全是由JVM自己控制的齿兔,需要加載哪個類,怎么加載都有JVM自己控制,別人也訪問不到這個類愧驱,所以這個ClassLoader是不遵守前面介紹的加載規(guī)則的慰技,它僅僅是一個類的加載工具而已,既沒有更高一級的父加載器组砚,也沒有子加載器吻商。

(2)ExtClassloader,這個類加載器有點特殊糟红,它是JVM自身的一部分艾帐,但是它的血統(tǒng)也不是很純正,它并不是JVM親自實現(xiàn)的盆偿,我們可以理解為這個類加載器是那些與這個大會合作單位的員工會員柒爸,這些會員既不是JVM內(nèi)部的,也和普通的外部會員不同事扭,所以就由這個類加載器來加載捎稚,它服務(wù)的特定目標(biāo)在System.getProperty("java.ext.dirs")目錄下。

(3)AppClassLoader求橄,這個類加載器就是專門為接待會員服務(wù)的今野,它的父類是ExtClassLoader。它服務(wù)的目標(biāo)是廣大普通會員罐农,所有在System.,getProperty("java.class.path")目錄下的類都可以被這個類加載器加載条霜,這個目錄就是我們常用到的classpath。

JVM加載class文件到內(nèi)存有兩種方式:

(1) 隱式加載:所謂隱式加載就是不通過在代碼里調(diào)用ClassLoader來加載需要的類涵亏,而是通過JVM來自動加載需要的類到內(nèi)存的方式宰睡。例如,當(dāng)我們在類中繼承或者引用某個類時气筋,JVM在解析當(dāng)前這個類時發(fā)現(xiàn)引用的類不在內(nèi)存中拆内,那么就會自動將這些類加載到內(nèi)存中。

(2)顯示加載:相反的顯示加載就是我們在代碼中通過ClassLoader類來加載一個類的方式裆悄。

如何加載class文件

ClassLoader加載一個class文件到JVM時需要經(jīng)過的步驟矛纹。
第一個階段是找到.class文件并把這個文件包含的字節(jié)碼加載到內(nèi)存中臂聋。
第二個階段又可以分為三個步驟光稼,分別是字節(jié)碼驗證、Class類數(shù)據(jù)結(jié)構(gòu)分析及相應(yīng)的內(nèi)存分配和最后的符號表的鏈接孩等。
第三階段是類中靜態(tài)屬性和初始化賦值艾君,以及靜態(tài)塊的執(zhí)行。
加載字節(jié)碼到內(nèi)存 其實在ClassLoader抽象類中并沒有定義如何去加載肄方,如何去找到指定類并把它的字節(jié)碼加載到內(nèi)存冰垄。需要實現(xiàn)findClass()方法。子類URLClassLoader是如何實現(xiàn)findClass()的权她,在URLClassLoader中通過一個URLClassPath類取得要加載的class文件字節(jié)流虹茶,而這個URLClassPath定義了到哪里去找這個class文件逝薪,如果找到了class文件,再讀取它的byte字節(jié)流蝴罪,通過調(diào)用defineClass()方法來創(chuàng)建類對象董济。
</p>

常見加載類錯誤分析

在執(zhí)行Java程序是經(jīng)常會碰到ClassNotFoundException和NoClassDefFoundError兩個異常,它們都和類加載有關(guān)要门。
(1) ClassNotFoundException

當(dāng)JVM要加載指定文件的字節(jié)碼到內(nèi)存時虏肾,并沒有找到這個文件對應(yīng)的字節(jié)碼。解決的辦法就是檢查在當(dāng)前的classpath目錄下有沒有指定的文件的存在欢搜,如果不知道當(dāng)前classpath路徑封豪,可以通過命令獲取:

this.getClass().getClassLoader().getResource("").toString()  

(2) NoClassDefFoundError

常出現(xiàn)在第一次使用命令執(zhí)行java類 ???例如:

java -cp example.jar Example

這里是因為在命令行中沒有加類的包名???正確的寫法:

 java -cp example.jar  net.aaa.Example

(3) UnstatusfiledLinkError
(4) ClassCastException
(5) ExceptionInInitializerError

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末炒瘟,一起剝皮案震驚了整個濱河市吹埠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌疮装,老刑警劉巖藻雌,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異斩个,居然都是意外死亡胯杭,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進(jìn)店門受啥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來做个,“玉大人,你說我怎么就攤上這事滚局【优” “怎么了?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵藤肢,是天一觀的道長太闺。 經(jīng)常有香客問我,道長嘁圈,這世上最難降的妖魔是什么省骂? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮最住,結(jié)果婚禮上钞澳,老公的妹妹穿的比我還像新娘。我一直安慰自己涨缚,他們只是感情好轧粟,可當(dāng)我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般兰吟。 火紅的嫁衣襯著肌膚如雪通惫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天混蔼,我揣著相機(jī)與錄音讽膏,去河邊找鬼。 笑死拄丰,一個胖子當(dāng)著我的面吹牛府树,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播料按,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼奄侠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了载矿?” 一聲冷哼從身側(cè)響起垄潮,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎闷盔,沒想到半個月后弯洗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡逢勾,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年牡整,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片溺拱。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡逃贝,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出迫摔,到底是詐尸還是另有隱情沐扳,我是刑警寧澤,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布句占,位于F島的核電站沪摄,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏纱烘。R本人自食惡果不足惜杨拐,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望凹炸。 院中可真熱鬧戏阅,春花似錦、人聲如沸啤它。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽变骡。三九已至离赫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間塌碌,已是汗流浹背渊胸。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留台妆,地道東北人翎猛。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像接剩,于是被迫代替她去往敵國和親切厘。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,060評論 2 355

推薦閱讀更多精彩內(nèi)容