類加載機制和雙親委派模型
1. 類加載機制
JVM將.class文件加載到內(nèi)存(方法區(qū))中,并對數(shù)據(jù)進行解析和初始化,最終形成被JVM直接使用的Java類型。
類的加載需要分成7個階段,分別是:加載、驗證、準(zhǔn)備、解析、初始化、使用和卸載。一般情況下我們只關(guān)注前5個階段。其中驗證、準(zhǔn)備和解析又統(tǒng)稱為連接階段。
2. 前5個階段
加載:在這個階段,虛擬機需要完成以下三個事情:
- 通過一個類的全限定名來獲取定義此類的二進制字節(jié)流(這個動作是類加載器完成的);
- 將這個字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)換成方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu);
- 在內(nèi)存中生成一個代表這個類的java.lang.Class對象,作為方法區(qū)這個類的各種數(shù)據(jù)的訪問入口。
驗證:驗證類數(shù)據(jù)信息是否符合JVM規(guī)范,是否是一個有效的字節(jié)碼文件。
準(zhǔn)備:給類靜態(tài)變量分配內(nèi)存空間,并初始化(與程序無關(guān),系統(tǒng)初始化)。
解析:將常量池中所有的符號引用轉(zhuǎn)成直接引用。
初始化:負(fù)責(zé)將所有static域按照程序指定操作對應(yīng)執(zhí)行(給static變量賦值,執(zhí)行static代碼塊的內(nèi)容)。
上述階段沒有嚴(yán)格的先后執(zhí)行順序,通常都是交叉執(zhí)行的。
3. 類加載器的分類
虛擬機設(shè)計團隊把類加載階段中的“通過一個類的權(quán)限定名來獲取此類的二進制字節(jié)流”這個動作放到JVM外部去實現(xiàn),以便讓程序自己決定如何去獲取所需要的類,實現(xiàn)這個代碼的模塊成為“類加載器”。
對于任意一個類,都需要由加載它的類和這個類本身一同確立其在Java虛擬機中的唯一性。
從JVM的角度來講,只存在兩種不同的類加載器,一個是啟動類加載器,使用C++實現(xiàn),是虛擬機的一部分;一個就是其他類加載器,使用java語言實現(xiàn),獨立于虛擬機外部,并且全部繼承自抽象類java.lang.ClassLoader。
從開發(fā)人員的角度,類加載器還可以分的更細(xì)致一點:
啟動類加載器
在HotSpot虛擬機中,BootStrap ClassLoader用C++語言編寫并嵌入到JVM內(nèi)部,主要加載JAVA_HOME/lib目錄下的所有類,或者加載由選項-Xbootclasspath指定的路徑下的類。
拓展類加載器
Extension ClassLoader繼承ClassLoader類,由sun.misc.Launcher$ExtClassLoader實現(xiàn),加載JAVA_HOME/lib/ext目錄中的所有類庫,或者被java.ext.dirs系統(tǒng)變量所指定的路徑中的所有類庫。
應(yīng)用程序加載器
Application ClassLoader由sun.misc.Launcher$AppClassLoader實現(xiàn),由于這個類加載器是ClassLoader中的getSystemClassLoader()方法的返回值類型,所以一般也稱它為系統(tǒng)類加載器。它負(fù)責(zé)加載用戶類路徑(ClassPath)上所指定的類庫,如果程序中沒有自定義過自己的類加載器,一般情況下這個就是程序中默認(rèn)的類加載器。
除此之外,還可以定義自己的類加載器。
4. 雙親委派模型
當(dāng)一個類加載器收到類加載任務(wù)時,立即將任務(wù)委派給它的父類加載器執(zhí)行,直至委派給最高層的啟動類加載器為止。只有當(dāng)父類反饋自己無法完成這個加載請求(它的搜索范圍中沒有找到所需的類)時,子加載器才會嘗試自己去加載。

作用:雙親委派模型可以保證全限名執(zhí)行的類,只被加載一次。并且Java類隨著它的類加載器一起具備了一種帶有優(yōu)先級的層次關(guān)系。
雙親委派模型不具有強制性約束,是Java設(shè)計者推薦的類加載器實現(xiàn)的方式。父子類的實現(xiàn)不是通過繼承而是通過組合的方式來復(fù)用父類的代碼。
雙親委派模型對于保證Java程序的穩(wěn)定運行很重要。但是它的實現(xiàn)卻非常簡單,實現(xiàn)代碼都集中在java.lang.ClassLoader的loadClass()方法中。
記錄自《深入理解Java虛擬機》的筆記,供自己以后復(fù)習(xí)參考