java.lang.ClassLoader類概述:
中文文檔中對ClassLoader類的定義如下:
從文檔中對ClassLoader類的介紹可以總結(jié)出這個類的作用就是根據(jù)一個指定的類的全限定名,找到對應(yīng)的Class字節(jié)碼文件,然后加載它轉(zhuǎn)化成一個java.lang.Class類的一個實例.
類加載器的劃分:
大部分java程序會使用以下3中系統(tǒng)提供的類加載器:
啟動類加載器(Bootstrap ClassLoader):
這個類加載器負(fù)責(zé)將\lib目錄下的類庫加載到虛擬機內(nèi)存中,用來加載java的核心庫,此類加載器并不繼承于java.lang.ClassLoader,不能被java程序直接調(diào)用,代碼是使用C++編寫的.是虛擬機自身的一部分.
擴展類加載器(Extendsion ClassLoader):
這個類加載器負(fù)責(zé)加載\lib\ext目錄下的類庫,用來加載java的擴展庫,開發(fā)者可以直接使用這個類加載器.
應(yīng)用程序類加載器(Application ClassLoader):
這個類加載器負(fù)責(zé)加載用戶類路徑(CLASSPATH)下的類庫,一般我們編寫的java類都是由這個類加載器加載,這個類加載器是CLassLoader中的getSystemClassLoader()方法的返回值,所以也稱為系統(tǒng)類加載器.一般情況下這就是系統(tǒng)默認(rèn)的類加載器.
除此之外,我們還可以加入自己定義的類加載器,以滿足特殊的需求,需要繼承java.lang.ClassLoader類.
類加載器之間的層次關(guān)系如下圖:
使用代碼觀察一下類加載器:
package com.wang.test;publicclass TestClassLoader {
? ? publicstaticvoid main(String[] args) {
? ? ? ? ClassLoader loader = TestClassLoader.class.getClassLoader();
? ? ? ? System.out.println(loader.toString());
? ? ? ? System.out.println(loader.getParent().toString());
? ? ? ? System.out.println(loader.getParent().getParent());
? ? }
}
觀察打印結(jié)果:
sun.misc.Launcher$AppClassLoader@500c05c2
sun.misc.Launcher$ExtClassLoader@454e2c9c
null
第一行打印的是應(yīng)用程序類加載器(默認(rèn)加載器),第二行打印的是其父類加載器,擴展類加載器,按照我們的想法第三行應(yīng)該打印啟動類加載器的,這里卻返回的null,原因是getParent(),返回時null的話,就默認(rèn)使用啟動類加載器作為父加載器.
?類加載器的雙親委派模型:
雙親委派模型是一種組織類加載器之間關(guān)系的一種規(guī)范,他的工作原理是:如果一個類加載器收到了類加載的請求,它不會自己去嘗試加載這個類,而是把這個請求委派給父類加載器去完成,這樣層層遞進,最終所有的加載請求都被傳到最頂層的啟動類加載器中,只有當(dāng)父類加載器無法完成這個加載請求(它的搜索范圍內(nèi)沒有找到所需的類)時,才會交給子類加載器去嘗試加載.
這樣的好處是:java類隨著它的類加載器一起具備了帶有優(yōu)先級的層次關(guān)系.這是十分必要的,比如java.langObject,它存放在\jre\lib\rt.jar中,它是所有java類的父類,因此無論哪個類加載都要加載這個類,最終所有的加載請求都匯總到頂層的啟動類加載器中,因此Object類會由啟動類加載器來加載,所以加載的都是同一個類,如果不使用雙親委派模型,由各個類加載器自行去加載的話,系統(tǒng)中就會出現(xiàn)不止一個Object類,應(yīng)用程序就會全亂了.
Class.forname()與ClassLoader.loadClass():
Class.forname():是一個靜態(tài)方法,最常用的是Class.forname(String className);根據(jù)傳入的類的全限定名返回一個Class對象.該方法在將Class文件加載到內(nèi)存的同時,會執(zhí)行類的初始化.
如:?Class.forName("com.wang.HelloWorld");
ClassLoader.loadClass():這是一個實例方法,需要一個ClassLoader對象來調(diào)用該方法,該方法將Class文件加載到內(nèi)存時,并不會執(zhí)行類的初始化,直到這個類第一次使用時才進行初始化.該方法因為需要得到一個ClassLoader對象,所以可以根據(jù)需要指定使用哪個類加載器.
如:ClassLoader cl=.......;cl.loadClass("com.wang.HelloWorld");