類(lèi)加載器工作原理

1.首先咱們來(lái)聊一聊什么叫類(lèi)加載器

顧名思義趾痘,類(lèi)加載器(class loader)用來(lái)加載 Java 類(lèi)到 Java 虛擬機(jī)中每强,具體來(lái)說(shuō)是加載.class文件到j(luò)vm內(nèi)存排嫌。java源代碼(.java文件)在經(jīng)過(guò)java編譯器編譯(javac 指令)之后會(huì)生成一個(gè)或多個(gè)的.class文件惧蛹,當(dāng)需要生成該對(duì)象的實(shí)例時(shí)唬党,虛擬機(jī)會(huì)去常量池查找該類(lèi)是否被加載撩银,如果沒(méi)有被加載给涕,就會(huì)調(diào)用類(lèi)加載器來(lái)將.class文件中的二進(jìn)制流加載到內(nèi)存中。而加載二進(jìn)制流的工具 (實(shí)現(xiàn)這一動(dòng)作的代碼塊)就是我們所說(shuō)的類(lèi)加載器额获。

2.類(lèi)加載器的作用:

從上面可以知道够庙,類(lèi)加載器干的活就是將對(duì)應(yīng)類(lèi)的.class文件中的二進(jìn)制流加載到內(nèi)存空間。

注意:這里所說(shuō)的加載到內(nèi)存空間只是將二進(jìn)制流寫(xiě)入內(nèi)存抄邀,還并沒(méi)有將二進(jìn)制流的存儲(chǔ)結(jié)構(gòu)解析并寫(xiě)入方法區(qū)耘眨,這一步操作是在? 【類(lèi)加載】?? 【驗(yàn)證階段】 【文件格式驗(yàn)證階段】才完成

3.類(lèi)與類(lèi)加載器之間的關(guān)系

對(duì)于任意的一個(gè)類(lèi)境肾,都需要由加載它的類(lèi)加載器這個(gè)類(lèi)本身一同確立其在java虛擬機(jī)中唯一性

每一個(gè)類(lèi)加載器剔难,都擁有一個(gè)獨(dú)立的類(lèi)名稱(chēng)空間 (這也是為什么每個(gè)類(lèi)的初始化只會(huì)執(zhí)行一次的原因)

通俗的來(lái)講:比較兩個(gè)類(lèi)是否“相等”只有這兩個(gè)類(lèi)由同一個(gè)類(lèi)加載器加載的前提下才有意義奥喻。否則偶宫,即使這兩個(gè)類(lèi)來(lái)源于同一個(gè).class文件,被同一個(gè)虛擬機(jī)加載衫嵌,只要加載他們的類(lèi)加載器不同读宙,那么這兩個(gè)類(lèi)就必然不相等。


那么問(wèn)題來(lái)了:java如何判斷兩個(gè)對(duì)象是否"相等"楔绞?

分析這個(gè)問(wèn)題前先來(lái)復(fù)習(xí)兩個(gè)問(wèn)題结闸,對(duì)象的比較的? ==? 與? equals

大家都知道用 ==來(lái)比較是直接判斷當(dāng)前比較的兩個(gè)對(duì)象是不是同一個(gè)對(duì)象,也就是當(dāng)前兩個(gè)對(duì)象的指針指向的是不是同一片內(nèi)存區(qū)域酒朵,簡(jiǎn)單來(lái)說(shuō):== 的比較方式判斷的是 內(nèi)存地址 也就是? 是不是同一個(gè)對(duì)象桦锄。因?yàn)樘摂M機(jī)中在同一時(shí)刻一個(gè)內(nèi)存塊只能存放一個(gè)對(duì)象,也就是說(shuō)內(nèi)存地址是唯一的蔫耽。

equals的比較方法在繼承自O(shè)bject的子類(lèi)沒(méi)有重寫(xiě)equals方法之前調(diào)用的是父類(lèi)也就是Object的equals方法结耀。而Object的equals方法實(shí)現(xiàn)使用的就是 == 判斷兩個(gè)對(duì)象是不是同一個(gè)對(duì)象。

源碼:

public boolean equals(Object obj) {??? // Object的equals方法實(shí)現(xiàn)

???????????????? return ( this? ==? obj);

}

如果子類(lèi)重寫(xiě)了equals方法匙铡,則調(diào)用的是子類(lèi)自己的實(shí)現(xiàn)邏輯图甜,我們一般把equals比較的結(jié)果當(dāng)成是對(duì)象的值的比較,也就是 equals比較的是對(duì)象的? 值

hashcode與equals的關(guān)系

Object中有個(gè) hashcode方法鳖眼,這個(gè)方法默認(rèn)返回的是內(nèi)存地址生成的一個(gè) int 值(虛擬機(jī)的實(shí)現(xiàn)不同黑毅,可能有出入),也就是說(shuō)默認(rèn)的hashcode是唯一的(因?yàn)閮?nèi)存地址唯一)

但是如果重寫(xiě)了Object的hashcode方法钦讳,那么hashcode的生成規(guī)則是由子類(lèi)自己決定矿瘦,與內(nèi)存地址就無(wú)關(guān)了(只是與當(dāng)前對(duì)象的內(nèi)存地址無(wú)關(guān)了枕面,其實(shí)質(zhì)還是通過(guò)對(duì)象的某些字段的內(nèi)存地址生成的int值)。

所以對(duì)象是否相等這里要分成三種情況來(lái)討論

1.沒(méi)有重寫(xiě) 對(duì)象的equals 與 hashcode 方法

如果對(duì)象沒(méi)有重寫(xiě)equals方法缚去,那么比較的是兩個(gè)對(duì)象的 hashcode(內(nèi)存地址根據(jù)一定的規(guī)則生成)潮秘,實(shí)質(zhì)上也就是對(duì)象的內(nèi)存地址,更通俗一點(diǎn)就是兩個(gè)? 是不是同一個(gè)對(duì)象

此處 hashcode 不相等易结,像個(gè)對(duì)象必然不相等 枕荞,反之亦然

2.重寫(xiě)了 equals方法,但是沒(méi)有重寫(xiě)hashcode方法

如果重寫(xiě)了equals方法衬衬,那么我們就是根據(jù) 自己定義的equals方法 比較對(duì)象的值买猖。由于沒(méi)有重寫(xiě)hashcode方法,那么hashcode的生成規(guī)則依舊是根據(jù)? 內(nèi)存按照一定規(guī)則生成

此處分為兩種情況:

1.如果兩個(gè)對(duì)象的equals 方法為真滋尉,但他們的 hashcode不一定相同.

2.如果兩個(gè)對(duì)象的hashcode相同玉控,那么他們是同一個(gè)對(duì)象,當(dāng)然equals會(huì)為真

3.重寫(xiě)了equals 與 hashcode 方法

重寫(xiě)了hashcode方法狮惜,那么hashcode就是根據(jù)自己定義的規(guī)則生成高诺,與內(nèi)存地址無(wú)關(guān)了

如果重寫(xiě)了equals與hashcode方法那么比較的規(guī)則就是與Object的基本一致,唯一不同的是碾篡,調(diào)用的是子類(lèi)中的equals與hashcode方法

此處如果hashcode相同虱而,那么兩個(gè)對(duì)象比較的euqls方法為真,反之亦然

所以在Object的equals方法的注釋里有這么一段話(huà):

* Note that it is generally necessary to override the {@code hashCode}

* method whenever this method is overridden, so as to maintain the

* general contract for the {@code hashCode} method, which states

* that equal objects must have equal hash codes.

大概意思也就是:為了維護(hù) hashcode 方法的一般合約开泽,即:相同的對(duì)象必須要具備相同的哈希值牡拇,在重寫(xiě)了equals 方法后?? 有必要?? 重寫(xiě) hashcode方法注意這里是有必要穆律,沒(méi)有一定 強(qiáng)制重寫(xiě)惠呼。

重寫(xiě)了equals卻沒(méi)有重寫(xiě)hashcode,一般不會(huì)有什么問(wèn)題峦耘,但要是要用到hashcode作為比較的條件的時(shí)候才會(huì)有問(wèn)題剔蹋,比方說(shuō)對(duì)象作為map的Key等。

hashCode方法的主要作用是為了配合基于散列的集合一起正常運(yùn)行辅髓,這樣的散列集合包括HashSet泣崩、HashMap以及HashTable。


扯遠(yuǎn)了洛口,言歸正傳矫付。上面講到了類(lèi)加載器的原理與作用,下面來(lái)分析一下類(lèi)加載器的類(lèi)型第焰。

4.類(lèi)加載器的分類(lèi)

從java虛擬機(jī)的角度來(lái)講技即,只分為兩種類(lèi)加載器,一種叫做啟動(dòng)類(lèi)加載器樟遣,這個(gè)加載器有C++實(shí)現(xiàn)而叼,是虛擬機(jī)的一部分。另外一種就是其他的類(lèi)加載器豹悬,這些類(lèi)都是有java語(yǔ)言實(shí)現(xiàn)葵陵,獨(dú)立于虛擬機(jī)之外,并且都有一個(gè)共同點(diǎn):繼承自抽象類(lèi)java.lang.ClassLoader瞻佛。

從java開(kāi)發(fā)人員的角度來(lái)看脱篙,分的更加細(xì)致,絕大部分的java程序都會(huì)提供以下三種系統(tǒng)類(lèi)加載器伤柄。

1)啟動(dòng)類(lèi)加載器(Bootstrap ClassLoader 引導(dǎo)類(lèi)加載器),這個(gè)類(lèi)負(fù)責(zé)將放在<JAVA_HOME>\lib目錄下绊困,并且是虛擬機(jī)識(shí)別的(僅僅按照文件名識(shí)別,名字不符合的類(lèi)庫(kù)即使在lib目錄下也不會(huì)被夾在)類(lèi)庫(kù)加載到虛擬機(jī)內(nèi)存中适刀。啟動(dòng)類(lèi)加載器無(wú)法被java程序直接引用秤朗,如果要把加載請(qǐng)求委派給啟動(dòng)類(lèi)加載器,那就直接用null代替即可笔喉。

2)擴(kuò)展類(lèi)加載器(Extension ClassLoader)負(fù)責(zé)加載<JAVA_HOME>\lib\ext目錄下的類(lèi)庫(kù)

3)應(yīng)用程序類(lèi)加載器(Application ClassLoader)也稱(chēng)為系統(tǒng)類(lèi)加載器取视,負(fù)責(zé)加載用戶(hù)類(lèi)路徑上所指定的類(lèi)庫(kù),如果應(yīng)用程序中沒(méi)有自定義過(guò)自己的類(lèi)加載器常挚,一般情況下這個(gè)就是程序中默認(rèn)的類(lèi)加載器作谭。通俗的來(lái)講:一般情況下,我們自己寫(xiě)的類(lèi)是由這個(gè)加載器加載奄毡。

雙親委派模型? 如下圖所示:

雙親委派模型

這個(gè)模型執(zhí)行的總體意思也就是:如果一個(gè)類(lèi)收到了類(lèi)加載請(qǐng)求折欠,它首先自己不會(huì)去加載這個(gè)類(lèi),而是將這個(gè)請(qǐng)求委派給父類(lèi)的加載器去完成吼过,父類(lèi)的加載器也不會(huì)首先去加載锐秦,他會(huì)將這個(gè)請(qǐng)求委派給自己的父類(lèi)去完成,如此往復(fù)直到頂層的 啟動(dòng)類(lèi)加載器那先。只有當(dāng)父類(lèi)加載器反饋說(shuō)自己無(wú)法完成這個(gè)加載請(qǐng)求時(shí)(在它的搜索范圍類(lèi)沒(méi)有找到所需的類(lèi))农猬,父類(lèi)會(huì)一層一層往下通知,子類(lèi)加載器才會(huì)自己去加載這個(gè)類(lèi)售淡。

通俗來(lái)講就是這樣:

兒子需要一個(gè)玩具月亮斤葱,就跟老爹講,老爹懶得理他揖闸,就跟自己的老爹說(shuō)揍堕,你孫子要個(gè)月亮,爺爺一聽(tīng)孫子要個(gè)月亮汤纸,就在自己力所能及的范圍內(nèi)搜索衩茸,結(jié)果發(fā)現(xiàn)自己找不到,然后爺爺就對(duì)爸爸說(shuō)贮泞,兒子楞慈,我找不到孫子要的月亮幔烛,還是你自己來(lái)找吧,于是爸爸也在自己的搜索范圍類(lèi)搜索囊蓝,發(fā)現(xiàn)自己也找不到這個(gè)月亮饿悬,于是也對(duì)兒子說(shuō),兒子聚霜,你老子找不到這個(gè)月亮狡恬,這個(gè)事兒呀還是得你自己來(lái),兒子一聽(tīng)你們都找不到那還是我自己來(lái)吧蝎宇,自己找找找呀找到了弟劲,拿著月亮玩去了,要是找遍了沒(méi)找到姥芥,兒子就躲一邊哭(報(bào)找不到類(lèi)的異常)

這個(gè)稱(chēng)之為雙親委派模型兔乞,這個(gè)模型的作用是java類(lèi)隨著他得類(lèi)加載器一起具備了一種帶有優(yōu)先層次的關(guān)系。例如類(lèi)java.lang.Object,它存放在rt.jar中撇眯,無(wú)論哪一個(gè)類(lèi)加載器要加載這個(gè)類(lèi)报嵌,最終都是委派給頂端的啟動(dòng)類(lèi)加載器去加載,因此Object類(lèi)在程序的各種類(lèi)加載環(huán)境中都是同一個(gè)類(lèi)熊榛。相反锚国,如果不是用雙親委派模型,由各個(gè)類(lèi)加載器自行去加載的話(huà)玄坦,如果用戶(hù)自己編寫(xiě)了一個(gè)java.lang.Object的類(lèi)血筑,并放在classPath中,那么系統(tǒng)中將出現(xiàn)多個(gè)不同的Object類(lèi)煎楣,java體系中最基礎(chǔ)的行為也無(wú)法保證豺总。

雙親委派模型對(duì)于保證java程序的穩(wěn)定運(yùn)行很重要,但實(shí)現(xiàn)對(duì)相當(dāng)簡(jiǎn)單邏輯很清楚:先檢查類(lèi)是否被加載過(guò)择懂,若沒(méi)有就調(diào)用父加載器的loadClass方法喻喳,若父加載器為空則默認(rèn)使用啟動(dòng)類(lèi)加載器作為父加載器。如果父加載器加載失敗困曙,拋出異常表伦,再調(diào)用自己的findClass方法進(jìn)行加載。

雙親委派模型中的父子關(guān)系不是由繼承關(guān)系實(shí)現(xiàn)的慷丽,而是以組合關(guān)系來(lái)復(fù)用父加載器的代碼

雙親委派模型被廣泛應(yīng)用于之后幾乎所有的java程序蹦哼,但卻并不是一個(gè)強(qiáng)制的模型,而是設(shè)計(jì)者推薦給開(kāi)發(fā)者的一種類(lèi)加載實(shí)現(xiàn)方式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末要糊,一起剝皮案震驚了整個(gè)濱河市纲熏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖局劲,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件勺拣,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡容握,警方通過(guò)查閱死者的電腦和手機(jī)宣脉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)剔氏,“玉大人,你說(shuō)我怎么就攤上這事竹祷√铬耍” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵塑陵,是天一觀的道長(zhǎng)感憾。 經(jīng)常有香客問(wèn)我,道長(zhǎng)令花,這世上最難降的妖魔是什么阻桅? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮兼都,結(jié)果婚禮上嫂沉,老公的妹妹穿的比我還像新娘。我一直安慰自己扮碧,他們只是感情好趟章,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著慎王,像睡著了一般蚓土。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上赖淤,一...
    開(kāi)封第一講書(shū)人閱讀 49,071評(píng)論 1 285
  • 那天蜀漆,我揣著相機(jī)與錄音,去河邊找鬼咱旱。 笑死确丢,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的莽龟。 我是一名探鬼主播蠕嫁,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼毯盈!你這毒婦竟也來(lái)了剃毒?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎赘阀,沒(méi)想到半個(gè)月后益缠,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡基公,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年幅慌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片轰豆。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡胰伍,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出酸休,到底是詐尸還是另有隱情骂租,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布斑司,位于F島的核電站渗饮,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏宿刮。R本人自食惡果不足惜互站,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望僵缺。 院中可真熱鬧胡桃,春花似錦、人聲如沸谤饭。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)揉抵。三九已至亡容,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間冤今,已是汗流浹背闺兢。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留戏罢,地道東北人屋谭。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像龟糕,于是被迫代替她去往敵國(guó)和親桐磁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345