數組
引導類加載器主要加載的class是jdk自己的類庫(JAVA_HOME\lib目錄下的jar文件),這些類庫都是jdk核心的類庫(rt.jar),也是最重要的,所以由這個加載器去完成加載和初始化。而且這個加載器是使用C語言實現的。緩存
擴展類加載器的主要租用就是加載jdk的擴展包的jar文件(JAVA_HOME\lib\ext目下的jar文件),這些文件是JDK的擴展類庫。安全
系統了加載器的核心做用就是加載classpath路徑下的class文件以及jar文件,這些類庫一般由開發人員本身編寫的,所以這些類都是經過系統類加載完成加載。jvm
在執行類加載的時候,最早由系統類加載器開始,但它會把加載的執行權先交給擴展類加載器,一樣,擴展類加載器也會將加載的執行權交給引導類加載器,最終由引導類加載器開始加載,若是須要加載的類庫不是引導類加載器加載的範疇,那麼就會將加載權交回給擴展類加載器。一樣,若是類庫不是擴展類加載器加載的範疇,最後就交由給系統類加載器來完成,這個過程就是委託。這樣作的目的室爲了保證系統類庫加載時的安全性,如:Object、String類等等,這些都應該由引導類加載器來完成,不該該交由其餘類加載器,由於,若是這些類庫加載的後能夠由用戶來進行操做,那麼就可會致使類的不安全。例如:用戶能夠重載或修改類中的方法,這是絕對禁止的。ide
除了引導到類加載器是有C語言來實現之外,其餘的類加載器都是繼承自ClassLoader這個類,而這個類中提供了相應的加載API來完成類加載以及初解析和始化的過程。this
API | 說明 |
---|---|
getParent() | 獲取上一級的類加載器 |
loadClass(String name) | 加載名稱爲name的類,返回的是一個Class實例,在此方法中會間接調用findClass方法 |
findClass(String name) | 加載名稱爲name的類,返回的是一個Class實例。一般自定義類加載器時,會重寫此方法。 |
findLoadedClass(String name) | 檢查名稱爲name的Class是否已經加載過,返回的是一個Class實例,若是Class爲null,就表示未加載,不然就是已經加載 |
defineClass(String name, byte[] b, int off, int len) | 將字節數組b的二進制數據轉換成Java中的Class對象 |
resolveClass(Class c) | 解析並鏈接到指定的Class |
咱們也能夠自定義類加載器,只須要繼承ClassLoader,一般須要重寫父類的findClass方法。須要注意的是,自定義類加載器它的上一級的類加載器是AppClassLoader,也會遵循委託的模式。spa
示例:對象
public class DemoClassLoader extends ClassLoader {
/**
* 類加載的根路徑
*/
private String loadRootPath;
public DemoClassLoader(String loadRootPath){
this.loadRootPath = loadRootPath;
}
/**
* 重寫父類的findClass方法
* @param name 須要加載的完整類名
* @return
* @throws ClassNotFoundException
*/
使用:blog
public class Main {
public static void main(String[] args) throws Exception{
//獲取當前系統的用戶目錄
String rootPath = System.getProperty("user.home")+File.separator;
DemoClassLoader c1 = new DemoClassLoader(rootPath);
Class clazz = cl.loadClass("Hello");
//建立類實例
Object hello = clazz.newInstance();
Object hello2 = clazz.newInstance();
System.out.println(hello);
System.out.println(hello2);
//獲取當前Class對象的類加載器
System.out.println(clazz.getClassLoader());
}
}
繼承