雙親委派機制

java面試總結 -------雙親委派模型

雙親委派模型是類加載器中一個重要的知識點。


類加載器模型

在這裏插入圖片描述
根據上圖類加載模型,類加載器由三部分組成,

  • 位於最上端也就是頂層父類的是根類加載器,它只加載%JAVA_HOME%/jre/lib/ext,此路徑下的所有classes目錄以及java.ext.dirs系統變量指定的路徑中類庫,此加載器由c++實現。
  • 然後下一層即根類加載器的子類加載器是拓展類加載器,由根類加載器加載,拓展類加載器只加載%JAVA_HOME%/jre/lib/ext,此路徑下的所有classes目錄以及java.ext.dirs系統變量指定的路徑中類庫。
  • 再下面就是應用類加載器,由拓展類加載器加載,應用類加載器爲Java默認加載器.
  • 然後再下面就是用戶的自定義加載器,由應用類加載器加載。

所以,從上到下爲父子關係,且三個加載器中除了根類加載器,拓展類加載器應用類加載器,有且只有一個父加載器。

雙親委託機制流程(見上圖)

  • 當一個類需要加載時,當前ClassLoader首先從自己已經加載的類中查詢是否此類已經加載,如果已經加載則直接返回原來已經加載的類。且每個類加載器都有自己的加載緩存,當一個類被加載了以後就會放入緩存,等下次加載的時候就可以直接返回了。
  • 如果當前類沒有加載,則會向父加載器查詢是否加載,若有,則返回類,若無,再向父加載器的父加載器查詢,周而復始下去,知道查詢到了根類加載器。
  • 如果根類加載器有,則返回,若無,則從根類加載器向下嘗試是否能加載,再從根類加載器嘗試是否能加載,不能則交給子類嘗試加載,周而復始直到能加載此類爲止。
  • 一般來說,用戶的自定義類均從應用類加載器加載,即從下往上找是否加載到根類加載器,再從上往下交給應用類加載器加載完成並返回。

實例詳解

public class MyTest5 {
    public static void main(String[] args) throws Exception{
        Class<?> clazz = Class.forName("java.lang.String");
        System.out.println(clazz.getClassLoader());
    }
}

在這個例子中,我們先用Class.forName獲得了String的類,然後使用getClassLoader方法獲得該類的加載器,在ClassLoadergetClassLoader方法源碼中,有這麼一行註釋:

Returns the class loader for the class. Some implementations may use
null to represent the bootstrap class loader. This method will return
null in such implementations if this class was loaded by the bootstrap
class loader.

該註釋大概意思時,該方法返回類的類加載器,如果該類的加載器是根類加載器就返回null。
由於String方法是屬於jt.jar包的所以由根類加載加載,輸出結果爲null。

public class MyTest5 {
    public static void main(String[] args) throws Exception{
        Class<?> clazz = Class.forName("classloader.MyTest5");
        System.out.println(clazz.getClassLoader());
    }
}

這裏我們輸出用戶自定義類的類加載器,由雙親委派機制可以得出,該類的類加載器爲應用類加載器,所以它的輸出結果爲:
在這裏插入圖片描述
即應用類加載器(AppClassLoader)

另:getClassLoader方法不是對類的主動使用

public class MyTest6 {
    public static void main(String[] args) {
        ClassLoader classLoader=ClassLoader.getSystemClassLoader();
        while (null!=classLoader){
            System.out.println(classLoader);
            classLoader = classLoader.getParent();
        }
        System.out.println(classLoader);
    }
}

在這段代碼中,我們先獲得了系統類加載器(即應用類加載器),然後循環輸出父類直到爲null爲止,
該代碼輸出結果爲:
在這裏插入圖片描述
從這張圖中,可以看出,系統加載器的父加載器是拓展類加載器,拓展類加載器的父加載器是根類加載器
(輸出爲null)
所以從實例三可以看出類加載器的層次關係。

幾個重要api

  • clazz.getClasLoader():獲得當前類的ClassLoader
  • Thread.currentThread().getContextClassLoader():獲得當前線程上下文的ClassLoader
  • ClassLoader.getSystemCassLoader():獲得系統的ClassLoader
  • DriverMangager,getCallerClassLoader():獲得調用者的ClassLoader

資料:雙親委託機制

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章