類加載器
首先應該明確jvm有公開的標準,並且有很多實現版本,最爲常用的就是HotSpot版(這個版本的jvm是由c++語言進行實現)。
其次jvm的作用:JVM中類加載器的作用就是:加載class字節碼文件,加載並初始化Class。
過程如圖所示:(簡略圖)
java中類加載器有4種:由高到低的排序
1.虛擬機自帶的加載器
2.啓動類(根)加載器 (位於jdk的lib中的 rt.jar)
3.擴展類加載器(位於jre/lib/ext目錄下)
4.應用程序(系統類)加載器
它們的執行順序是4321,由高到低(1234)是父子類關係。
當明確過這些概念後就可以瞭解雙親委派機制。
public class Student {
public static void main(String[] args) {
Student s1 = new Student();
Class<? extends Student> aClass1 = s1.getClass();
ClassLoader classLoader = aClass1.getClassLoader();
System.out.println(classLoader);
//輸出結果AppClassLoader
System.out.println(classLoader.getParent());
//輸出結果ExtClassLoader 擴展類加載器 jre/lib/ext
System.out.println(classLoader.getParent().getParent());
//輸出結果 null 可能造成的原因1.不存在 2.java程序獲取不到 rt.jar
//而null是因爲 jvm是由c++寫的,能夠獲取到,但是無法調用
}
}
雙親委派機制
1.當類加載器需要加載初始類(即收到加載類的請求時),並不會立即執行,而是調用父類的類加載器去執行,當父類類加載器還存在父類時,則再由父類的上層類加載器執行,最終到達啓動類加載器進行執行。AppClassLoader—>ExtClassLoader—>Bootstrap ClassLoder
2.如果在啓動類加載器執行時,能夠加載到該類,則由啓動器加載類進行加載。
3.如果父類加載器無法加載這個類,就拋出異常,調用子類加載器,進行加載,依次往下執行,直到某各類加載器能夠完成加載。Bootstrap ClassLoder—>ExtClassLoader—>AppClassLoader
簡單地說就是:子類給父類,父類加載器能加載就優先加載,不能則父類再給子類類加載器。
這種機制首先能夠避免重複加載,其次能夠保護java的核心api不被破壞。
舉個例子:
大家有沒有想過寫一個和SreingAPI同名的類,即創建java.lang.String類,同時定義一個toString方法,那麼在String類中的main方法執行入口中去執行這個String 對象的toString方法,結果會如何呢?
package java.lang; //創建和系統StringAPI,同類名的String類
public class String {
public String toString(){
return "hello";
}
public static void main(String[] args) {
String s = new String();
System.out.println(s);
}
}`.
結果當然會報錯:錯誤信息如圖所示
原因就是:類加載器一層一層向上找,最終使用啓動類加載器,而啓動類加載器位於jdk的rt.jar,在這裏加載到的類時java的核心api:String.那麼就不會執行自己定義的String類,而在覈心API中並沒有main方法,因此保存會找不到。