Java類加載器原理

每個(gè)編寫的”.java”拓展名類文件都存儲著需要執(zhí)行的程序邏輯厢破,這些”.java”文件經(jīng)過Java編譯器編譯成拓展名為”.class”的文件缝裁,”.class”文件中保存著Java代碼經(jīng)轉(zhuǎn)換后的虛擬機(jī)指令扫皱,當(dāng)需要使用某個(gè)類時(shí),虛擬機(jī)將會加載它的”.class”文件捷绑,并創(chuàng)建對應(yīng)的class對象韩脑,將class文件加載到虛擬機(jī)的內(nèi)存,這個(gè)過程稱為類加載粹污,這里我們需要了解一下類加載的過程段多,如下:

image.png

加載:類加載過程的一個(gè)階段:通過一個(gè)類的完全限定查找此類字節(jié)碼文件,并利用字節(jié)碼文件創(chuàng)建一個(gè)Class對象

驗(yàn)證:目的在于確保Class文件的字節(jié)流中包含信息符合當(dāng)前虛擬機(jī)要求壮吩,不會危害虛擬機(jī)自身安全进苍。主要包括四種驗(yàn)證加缘,文件格式驗(yàn)證,元數(shù)據(jù)驗(yàn)證觉啊,字節(jié)碼驗(yàn)證拣宏,符號引用驗(yàn)證。

準(zhǔn)備:為類變量(即static修飾的字段變量)分配內(nèi)存并且設(shè)置該類變量的初始值即0(如static int i=5;這里只將i初始化為0杠人,至于5的值將在初始化時(shí)賦值)勋乾,這里不包含用final修飾的static,因?yàn)閒inal在編譯的時(shí)候就會分配了嗡善,注意這里不會為實(shí)例變量分配初始化辑莫,類變量會分配在方法區(qū)中,而實(shí)例變量是會隨著對象一起分配到Java堆中罩引。

解析:主要將常量池中的符號引用替換為直接引用的過程各吨。符號引用就是一組符號來描述目標(biāo),可以是任何字面量袁铐,而直接引用就是直接指向目標(biāo)的指針绅你、相對偏移量或一個(gè)間接定位到目標(biāo)的句柄。有類或接口的解析昭躺,字段解析忌锯,類方法解析,接口方法解析(這里涉及到字節(jié)碼變量的引用领炫,如需更詳細(xì)了解偶垮,可參考《深入Java虛擬機(jī)》)。

初始化:類加載最后階段帝洪,若該類具有超類似舵,則對其進(jìn)行初始化,執(zhí)行靜態(tài)初始化器和靜態(tài)初始化成員變量(如前面只初始化了默認(rèn)值的static變量將會在這個(gè)階段賦值葱峡,成員變量也將被初始化)砚哗。

這便是類加載的5個(gè)過程,而類加載器的任務(wù)是根據(jù)一個(gè)類的全限定名來讀取此類的二進(jìn)制字節(jié)流到JVM中砰奕,然后轉(zhuǎn)換為一個(gè)與目標(biāo)類對應(yīng)的java.lang.Class對象實(shí)例蛛芥,在虛擬機(jī)提供了3種類加載器,引導(dǎo)(Bootstrap)類加載器军援、擴(kuò)展(Extension)類加載器仅淑、系統(tǒng)(System)類加載器(也稱應(yīng)用類加載器),下面分別介紹

啟動(Bootstrap)類加載器

啟動類加載器主要加載的是JVM自身需要的類胸哥,這個(gè)類加載使用C++語言實(shí)現(xiàn)的涯竟,是虛擬機(jī)自身的一部分,它負(fù)責(zé)將 <JAVA_HOME>/lib路徑下的核心類庫或-Xbootclasspath參數(shù)指定的路徑下的jar包加載到內(nèi)存中,注意必由于虛擬機(jī)是按照文件名識別加載jar包的庐船,如rt.jar银酬,如果文件名不被虛擬機(jī)識別,即使把jar包丟到lib目錄下也是沒有作用的(出于安全考慮筐钟,Bootstrap啟動類加載器只加載包名為java捡硅、javax、sun等開頭的類)盗棵。

擴(kuò)展(Extension)類加載器

擴(kuò)展類加載器是指Sun公司(已被Oracle收購)實(shí)現(xiàn)的sun.misc.Launcher$ExtClassLoader類,由Java語言實(shí)現(xiàn)的北发,是Launcher的靜態(tài)內(nèi)部類纹因,它負(fù)責(zé)加載<JAVA_HOME>/lib/ext目錄下或者由系統(tǒng)變量-Djava.ext.dir指定位路徑中的類庫舆驶,開發(fā)者可以直接使用標(biāo)準(zhǔn)擴(kuò)展類加載器瓜浸。

系統(tǒng)(System)類加載器

也稱應(yīng)用程序加載器是指 Sun公司實(shí)現(xiàn)的sun.misc.Launcher$AppClassLoader先嬉。它負(fù)責(zé)加載系統(tǒng)類路徑j(luò)ava -classpath或-D java.class.path 指定路徑下的類庫单旁,也就是我們經(jīng)常用到的classpath路徑顶猜,開發(fā)者可以直接使用系統(tǒng)類加載器塘娶,一般情況下該類加載是程序中默認(rèn)的類加載器扰法,通過ClassLoader#getSystemClassLoader()方法可以獲取到該類加載器栓票。
  在Java的日常應(yīng)用程序開發(fā)中密任,類的加載幾乎是由上述3種類加載器相互配合執(zhí)行的颜启,在必要時(shí),我們還可以自定義類加載器浪讳,需要注意的是缰盏,Java虛擬機(jī)對class文件采用的是按需加載的方式,也就是說當(dāng)需要使用該類時(shí)才會將它的class文件加載到內(nèi)存生成class對象淹遵,而且加載某個(gè)類的class文件時(shí)口猜,Java虛擬機(jī)采用的是雙親委派模式即把請求交由父類處理,它一種任務(wù)委派模式透揣,下面我們進(jìn)一步了解它济炎。

雙親委派模式工作原理

雙親委派模式要求除了頂層的啟動類加載器外,其余的類加載器都應(yīng)當(dāng)有自己的父類加載器辐真,請注意雙親委派模式中的父子關(guān)系并非通常所說的類繼承關(guān)系须尚,而是采用組合關(guān)系來復(fù)用父類加載器的相關(guān)代碼,類加載器間的關(guān)系如下:


image.png

雙親委派模式是在Java 1.2后引入的侍咱,其工作原理的是恨闪,如果一個(gè)類加載器收到了類加載請求,它并不會自己先去加載放坏,而是把這個(gè)請求委托給父類的加載器去執(zhí)行咙咽,如果父類加載器還存在其父類加載器,則進(jìn)一步向上委托淤年,依次遞歸钧敞,請求最終將到達(dá)頂層的啟動類加載器蜡豹,如果父類加載器可以完成類加載任務(wù),就成功返回溉苛,倘若父類加載器無法完成此加載任務(wù)镜廉,子加載器才會嘗試自己去加載,這就是雙親委派模式愚战,即每個(gè)兒子都很懶娇唯,每次有活就丟給父親去干,直到父親說這件事我也干不了時(shí)寂玲,兒子自己想辦法去完成塔插,這不就是傳說中的實(shí)力坑爹啊拓哟?那么采用這種模式有啥用呢?
采用雙親委派模式的是好處是Java類隨著它的類加載器一起具備了一種帶有優(yōu)先級的層次關(guān)系想许,通過這種層級關(guān)可以避免類的重復(fù)加載,當(dāng)父親已經(jīng)加載了該類時(shí)断序,就沒有必要子ClassLoader再加載一次流纹。其次是考慮到安全因素,java核心api中定義類型不會被隨意替換违诗,假設(shè)通過網(wǎng)絡(luò)傳遞一個(gè)名為java.lang.Integer的類漱凝,通過雙親委托模式傳遞到啟動類加載器,而啟動類加載器在核心Java API發(fā)現(xiàn)這個(gè)名字的類诸迟,發(fā)現(xiàn)該類已被加載碉哑,并不會重新加載網(wǎng)絡(luò)傳遞的過來的java.lang.Integer,而直接返回已加載過的Integer.class亮蒋,這樣便可以防止核心API庫被隨意篡改扣典。可能你會想慎玖,如果我們在classpath路徑下自定義一個(gè)名為java.lang.SingleInterge類(該類是胡編的)呢贮尖?該類并不存在java.lang中,經(jīng)過雙親委托模式趁怔,傳遞到啟動類加載器中湿硝,由于父類加載器路徑下并沒有該類,所以不會加載润努,將反向委托給子類加載器加載关斜,最終會通過系統(tǒng)類加載器加載該類。但是這樣做是不允許铺浇,因?yàn)閖ava.lang是核心API包痢畜,需要訪問權(quán)限,強(qiáng)制加載將會報(bào)出如下異常

java.lang.SecurityException: Prohibited package name: java.lang

類加載器間的關(guān)系

我們進(jìn)一步了解類加載器間的關(guān)系(并非指繼承關(guān)系),主要可以分為以下4點(diǎn)

  • 啟動類加載器丁稀,由C++實(shí)現(xiàn)吼拥,沒有父類。

  • 拓展類加載器(ExtClassLoader)线衫,由Java語言實(shí)現(xiàn)凿可,父類加載器為null

  • 系統(tǒng)類加載器(AppClassLoader),由Java語言實(shí)現(xiàn)授账,父類加載器為ExtClassLoader

  • 自定義類加載器枯跑,父類加載器肯定為AppClassLoader。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末白热,一起剝皮案震驚了整個(gè)濱河市敛助,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌棘捣,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,640評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件休建,死亡現(xiàn)場離奇詭異乍恐,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)测砂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評論 3 395
  • 文/潘曉璐 我一進(jìn)店門茵烈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人砌些,你說我怎么就攤上這事呜投。” “怎么了存璃?”我有些...
    開封第一講書人閱讀 165,011評論 0 355
  • 文/不壞的土叔 我叫張陵仑荐,是天一觀的道長。 經(jīng)常有香客問我纵东,道長粘招,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,755評論 1 294
  • 正文 為了忘掉前任偎球,我火速辦了婚禮洒扎,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘衰絮。我一直安慰自己袍冷,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評論 6 392
  • 文/花漫 我一把揭開白布猫牡。 她就那樣靜靜地躺著胡诗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上乃戈,一...
    開封第一講書人閱讀 51,610評論 1 305
  • 那天褂痰,我揣著相機(jī)與錄音,去河邊找鬼症虑。 笑死缩歪,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的谍憔。 我是一名探鬼主播匪蝙,決...
    沈念sama閱讀 40,352評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼习贫!你這毒婦竟也來了逛球?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,257評論 0 276
  • 序言:老撾萬榮一對情侶失蹤苫昌,失蹤者是張志新(化名)和其女友劉穎颤绕,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體祟身,經(jīng)...
    沈念sama閱讀 45,717評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡奥务,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了袜硫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片氯葬。...
    茶點(diǎn)故事閱讀 40,021評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖婉陷,靈堂內(nèi)的尸體忽然破棺而出帚称,到底是詐尸還是另有隱情,我是刑警寧澤秽澳,帶...
    沈念sama閱讀 35,735評論 5 346
  • 正文 年R本政府宣布闯睹,位于F島的核電站,受9級特大地震影響担神,放射性物質(zhì)發(fā)生泄漏瞻坝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評論 3 330
  • 文/蒙蒙 一杏瞻、第九天 我趴在偏房一處隱蔽的房頂上張望所刀。 院中可真熱鬧,春花似錦捞挥、人聲如沸浮创。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽斩披。三九已至溜族,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間垦沉,已是汗流浹背煌抒。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留厕倍,地道東北人寡壮。 一個(gè)月前我還...
    沈念sama閱讀 48,224評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像讹弯,于是被迫代替她去往敵國和親况既。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評論 2 355

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