ClassLoader :public abstract class ClassLoader , extends Object
類加載器是負責加載類的對象。ClassLoader 類是一個抽象類。如果給定類的二進制名稱,那麼類加載
會試圖查找出或生成構成類定義數據。一般策略是將名稱轉換爲某個文件,然後從文件系統讀取該名稱的
“文件”,每個 Class 對象都包含一個對定義它的 ClassLoader 的引用。數組類的Class對象不是由類加載
創建的,而是由Java運行時根據需要自動創建。數組類的類加載器由Class.getClassLoader()返回,該加載
器與其元素類型的類加載器是相同的;如果該元素是基本類型,則該數組類沒有類加載器。
應用程序需要實現ClassLoader的子類,以擴展Java虛擬機動態加載類的方式。
類加載器通常由安全管理器使用,用於指示安全域。
ClassLoader 類使用委託模型來搜索類和資源。每個 ClassLoader 實例都有一個相關的父類加載器。
需要查找類或資源時,ClassLoader 實例會在試圖親自查找類或資源之前,將搜索類或資源的任務委託給其父
類加載器。虛擬機的內置類加載器(稱爲 "bootstrap class loader")本身沒有父類加載器,但是可以將它
用作 ClassLoader 實例的父類加載器。
通常情況下,Java 虛擬機以與平臺有關的方式,從本地文件系統中加載類。例如,在 UNIX 系統中,虛
擬機從 CLASSPATH 環境變量定義的目錄中加載類。
然而,有些類可能並非源自一個文件;它們可能源自其他來源(如網絡),也可能是由應用程序構造的。
defineClass 方法將一個 byte 數組轉換爲 Class 類的實例。這種新定義的類的實例可以使用
Class.newInstance 來創建。
類加載器所創建對象的方法和構造方法可以引用其他類。爲了確定引用的類,Java 虛擬機將調用最初創建
該類的類加載器的 loadClass 方法。
ClassLoader的類別:
*啓動類加載器(BootStrap)
*擴展類加載器(Extension)
*應用程序類加載器(AppClassLoader)
*用戶自定義加載器
一般我們自己寫的類用的都是AppClassLoader類加載器,就是下面的測試結果中,
獲取自己寫的類的類加載器是 sun.misc.Launcher$AppClassLoader@18b4aac2,而獲取String的
就是null,這個null就是BootStrap這個加載器,BootStrap類加載器相當於啓動類加載器、
應用程序類加載器的祖宗,若是用了BootStrap,由於BootStrap上一級已經沒有了,所以就用“null”來表示
|——————————————————————|
|BootStrap ClassLoader | $JAVA_HOME/jre/lib/rt.jar
|——————————————————————|
|
|——————————————————————|
|Extension ClassLoader | $JAVA_HOME/jre/lib/*.jar
|——————————————————————|
|
|——————————————————————|
|System ClassLoader | $CLASSPATH
|——————————————————————|
| |
| |
|————————————————————————| |————————————————————————|
|User-Defined ClassLoader| |User-Defined ClassLoader|
|————————————————————————| |————————————————————————|
|
|
|————————————————————————|
|User-Defined ClassLoader|
|————————————————————————|
這張圖就可以很清晰得看到:
1.所有在$Java_Home/jre/lib/rt.jar是通過BootStrap加載的
2.所有在$Java_Home/jre/lib/ext/*.jar是通過Extension加載的
3.所有在$CLASSPATH是通過SYSTEM加載的(應用程序類加載器也叫系統類加載器,加載當前應用的classpath
的所有類)
舉個例子:創建一個java.lang包,然後創建String類,打印一句話執行
package java.lang;
public class String{
public static void main(String[] args){
System.out.println("Hello World");
}
}
執行後報錯:錯誤:在類java.lang.String中找不到main方法,請將main方法定義爲public static
void main(String[] args),否則JavaFX應用程序類必須擴展javafx.application.Application
出現這種情況,涉及到雙親委派機制:
當一個類收到了類加載請求,他首先不會嘗試自己去加載這個類,而是把這個請求委派給父類去完成,
每一個層次類加載器都是如此,因此所有的加載請求都應該傳送到啓動類加載器中,只有當父類加載器反饋自己
無法完成這個請求的時候(在它的加載路徑下沒有找到所需加載的Class),子類加載器纔會嘗試自己去加載。
所以他的實際運行過程是這樣的:
ClassLoader收到String類的加載請求,先去BootStrap類中查找是否有這個類,沒有則反饋無法完成這個請
求,但是在rt.jar中找到了java.lang.String這個類,執行這個類,這個類中沒有定義main方法
所以上面的例子,他會找到jdk中java.lang.String這個類,這個類確實沒有main方法,簡單說它執行了
的類是JDK中java.lang.String這個類,而不是我們自己定義的類
雙親委派機制的優點:採用雙親委派的一個好處是比如加載位於 rt.jar 包中的類 java.lang.Object,
不管是哪個加載器加載這個類,最終都是委託給頂層的啓動類加載器進行加載,這樣就保證了使用不同的類加載
器最終得到的都是同樣一個 Object對象。