每天進(jìn)步一點點栖忠!
上一篇穿插了一段動態(tài)綁定和靜態(tài)綁定的知識咽瓷,這一篇我們回歸到類加載上來设凹,學(xué)習(xí)一下類加載的“加載”。
是不是讀起來有點拗口忱详,這是什么意思围来?
別迷糊,還記得上一篇的上一篇學(xué)習(xí)過的類加載過程嗎匈睁,里面有一個階段就是“加載(loading)”。
加載過程主要包括以下三點內(nèi)容:
1桶错、通過一個類的全限定名來獲取定義此類的二進(jìn)制字節(jié)流航唆。
全限定名也就是包名.類名的形式。如下圖所示院刁,當(dāng)我們在同一個類中糯钙,引用的兩個類名相同的類,都是StringUtils的時候,就需要使用全限定名org.apache.commons.lang.StringUtils進(jìn)行區(qū)分任岸,另一個沒有帶包名的再榄,則默認(rèn)使用import引入的包。
注意享潜,這里說的二進(jìn)制字節(jié)流困鸥,并沒有明確一定是從Class文件中獲取,這就演化出了一些其它形式剑按,比如:壓縮文件疾就,可以是jar包和war包;Applet可以從網(wǎng)絡(luò)中獲纫蘸猬腰;使用動態(tài)代理技術(shù)(CGLIB等)生成的二進(jìn)制流;通過其它文件生成猜敢,如jsp文件生成的class文件姑荷。還可以從數(shù)據(jù)庫讀取,等等……
另外缩擂,還有一個問題厢拭,如果我手動寫一個java.lang.System打成一個包加載到虛擬機(jī)中,是不是會對rt.jar包中的System產(chǎn)生影響呢撇叁?這里就要說說類加載器了供鸠。
java程序一般會用到三種類加載器:
1)啟動類加載器(Bootstrap
ClassLoader):負(fù)責(zé)加載JAVA_HOME\lib或者被-Xbootclasspath參數(shù)所指定的路徑中的目錄中,并且能被虛擬機(jī)識別的類庫到JVM內(nèi)存中陨闹,如果名稱不符合的類庫即使放在lib目錄中也不會被加載楞捂。這個類加載器是虛擬器自身的一部分,無法被Java程序直接引用(HotSpot中采用C++編寫)趋厉。
2)擴(kuò)展類加載器(Extension ClassLoader):該加載器主要是負(fù)責(zé)加載JAVA_HOME\lib\ext目錄下的類寨闹,或者java.ext.dirs指定目錄下的類,該加載器可以被開發(fā)者直接使用君账。
java.ext.dirs可以通過-Djava.ext.dirs命令進(jìn)行設(shè)置(web開發(fā)中很少會用到)繁堡,我們可以在系統(tǒng)屬性中取到。
運行結(jié)果如下乡数。
3)應(yīng)用程序類加載器(Application
ClassLoader):該類加載器也稱為應(yīng)用程序類加載器椭蹄,它負(fù)責(zé)加載用戶類路徑(Classpath)上所指定的類庫,開發(fā)者可以直接使用該類加載器净赴,如果應(yīng)用程序中沒有自定義過自己的類加載器绳矩,一般情況下這個就是程序中默認(rèn)的類加載器。
既然知道了實現(xiàn)類是什么玖翅,我們不妨打開類文件看一眼翼馆。
看起來是不是更直觀了割以,我們再生成AppClassLoader的類圖簡單看一下,對該類的繼承關(guān)系有一個大概的了解应媚。
在虛擬機(jī)實際的工作當(dāng)中严沥,類加載器之間是存在層次關(guān)系的,如下圖所示中姜,
這種包含優(yōu)先級的層次關(guān)系被稱為雙親委派模型消玄,即如果一個類加載器收到了一個類加載請求,它不會自己去嘗試加載這個類扎筒,而是把這個請求轉(zhuǎn)交給父類加載器去完成莱找。每一個層次的類加載器都是如此。因此所有的類加載請求都應(yīng)該傳遞到最頂層的啟動類加載器中嗜桌,只有到父類加載器反饋自己無法完成這個加載請求(在它的搜索范圍沒有找到這個類)時奥溺,子類加載器才會嘗試自己去加載。
那么也就是說當(dāng)虛擬機(jī)發(fā)現(xiàn)需要加載java.lang.System類的時候骨宠,會最先使用啟動類加載器去尋找浮定,避免了類被重復(fù)加載。
2层亿、將這個字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu)桦卒。
還記得我們最開始學(xué)習(xí)的虛擬機(jī)管理的數(shù)據(jù)區(qū)域的內(nèi)容嗎,虛擬機(jī)加載的類信息匿又,常量方灾,靜態(tài)變量,即時編譯器編譯的代碼等數(shù)據(jù)存儲在方法區(qū)碌更。
3裕偿、在內(nèi)存中生成一個代表這個類的java.lang.Class對象,作為方法區(qū)這個類的各種數(shù)據(jù)的訪問入口痛单。
Class對象是一個特殊的對象嘿棘,是用來創(chuàng)建其它對象的對象,經(jīng)常會用到的如Class.forName("className")方法旭绒,如下圖所示鸟妙,
這個方法運行后出現(xiàn)一個有意思的結(jié)果,第一個輸出為true挥吵,第二個為false重父。
因為作為參照的SameClassNameTest是由應(yīng)用程序加載器加載的,而obj2是使用自定義的類加載器ClassLoader加載后創(chuàng)建的蔫劣,所以并不相等坪郭,是不是很神奇?
喜歡文章或想一起學(xué)習(xí)的朋友可以關(guān)注我脉幢,給我點贊歪沃,我將會持續(xù)更新,有什么疑問或文中有不當(dāng)之處請給我留言嫌松,真誠地希望能與大家一起交流探討沪曙,學(xué)習(xí)進(jìn)步。