類的加載器
????類加載器(ClassLoader)杠河,即加載類的東西薛训。在我們使用一個類之前呐能,JVM(JAVA虛擬機)需要先將該類的字節(jié)碼文件(.class文件)從磁盤隶糕、網(wǎng)絡(luò)或其他來源加載到內(nèi)存中冈在,并對字節(jié)碼進行解析生成對應(yīng)的Class對象倒慧,這就是類加載器的功能。我們可以利用類加載器包券,實現(xiàn)類的動態(tài)加載纫谅。
? ? 類的字節(jié)碼可以來自于磁盤文件 *.class,也可以是 jar 包里的 *.class,也可以來自遠程服務(wù)器提供的字節(jié)流优烧,字節(jié)碼的本質(zhì)就是一個字節(jié)數(shù)組 []byte俺叭,它有特定的復(fù)雜的內(nèi)部格式。
延遲加載
????JVM 運行并不是一次性加載所需要的全部類的盹牧,它是按需加載俩垃,也就是延遲加載。程序在運行的過程中會逐漸遇到很多不認識的新類汰寓,這時候就會調(diào)用 ClassLoader 來加載這些類口柳。加載完成后就會將 Class 對象存在 ClassLoader 里面,下次就不需要重新加載了有滑。比如你在調(diào)用某個類的靜態(tài)方法時跃闹,首先這個類肯定是需要被加載的,但是并不會觸及這個類的實例字段毛好,那么實例字段的類別 Class 就可以暫時不必去加載望艺,但是它可能會加載靜態(tài)字段相關(guān)的類別,因為靜態(tài)方法會訪問靜態(tài)字段肌访。而實例字段的類別需要等到你實例化對象的時候才可能會加載找默。
各司其職
JVM 運行實例中會存在多個 ClassLoader,不同的 ClassLoader 會從不同的地方加載字節(jié)碼文件吼驶。JVM 中內(nèi)置了三個重要的 ClassLoader惩激,分別是:
BootStrap ClassLoader:負責(zé)加載 JVM 運行時核心類,這些類位于 JAVA_HOME/lib/rt.jar 文件中蟹演,我們常用內(nèi)置庫 java.xxx.* 都在里面风钻,比如 java.util.*、java.io.*酒请、java.nio.*骡技、java.lang.* 等等。這個 ClassLoader 比較特殊蚌父,它是由 C 代碼實現(xiàn)的哮兰,我們將它稱之為「根加載器」。
Extension ClassLoader:稱為擴展類加載器苟弛,負責(zé)加載Java的擴展類庫喝滞,默認加載JAVA_HOME/jre/lib/ext/目下的所有jar。比如 swing 系列膏秫、內(nèi)置的 js 引擎右遭、xml 解析器 等等,這些庫名通常以 javax 開頭缤削。
App ClassLoader:稱為系統(tǒng)類加載器窘哈,負責(zé)加載應(yīng)用程序classpath目錄下的所有jar和class文件。我們自己編寫的代碼以及使用的第三方 jar 包通常都是由它來加載的亭敢。main 方法執(zhí)行的時候滚婉,這第一個用戶類的加載器就是 AppClassLoader。
????jdk 內(nèi)置了一個 URLClassLoader帅刀,用戶只需要傳遞規(guī)范的網(wǎng)絡(luò)路徑給構(gòu)造器让腹,就可以使用 URLClassLoader 來加載遠程類庫和本地類庫远剩。ExtensionClassLoader 和 AppClassLoader 都是 URLClassLoader 的子類,從本地文件系統(tǒng)里加載類庫骇窍。
ClassLoader 傳遞性
? ??程序在運行過程中瓜晤,遇到了一個未知的類,虛擬機的策略是使用調(diào)用者 Class 對象(正在運行一個方法調(diào)用腹纳,這個方法掛在哪個類上面痢掠,那這個類就是調(diào)用者 Class 對象)的 ClassLoader 來加載當(dāng)前未知的類。每個 Class 對象里面都有一個 classLoader 屬性記錄了當(dāng)前的類是由誰來加載的嘲恍。因為 ClassLoader 的傳遞性足画,所有延遲加載的類都會由初始調(diào)用 main 方法的這個 ClassLoader 全全負責(zé),它就是 AppClassLoader佃牛。
雙親委派
? ???AppClassLoader 只負責(zé)加載 Classpath 下面的類庫锌云,如果遇到?jīng)]有加載的系統(tǒng)類庫怎么辦,AppClassLoader 必須將系統(tǒng)類庫的加載工作交給 BootstrapClassLoader 和 ExtensionClassLoader 來做吁脱,這就是雙親委派。這三個 ClassLoader 之間形成了級聯(lián)的父子關(guān)系彬向,每個 ClassLoader 都很懶兼贡,盡量把工作交給父親做,父親干不了了自己才會干娃胆。每個 ClassLoader 對象內(nèi)部都會有一個 parent 屬性指向它的父加載器遍希。