JVM 預定義類加載器 和 雙親委派機制

原文 - 關于Java類加載雙親委派機制的思考

JVM 預定義的三種類型類加載器:

類型 實現 負責加載類庫的路徑 開發者
啟動類
加載器
本地代碼 jre/lib 下面的類庫,如 rt.jar 無法操作
擴展類
加載器
ExtClassLoader jre/lib/ext 下面的類庫 或者
系統變量 java.ext.dir 指定位置中的類庫
可以操作
系統類
加載器
AppClassLoader 系統類路徑(CLASSPATH)中指定的類庫 可以操作

注:我們平時自己定義的類就是在 CLASSPATH 路徑指定的系統類。

雙親委派機制

某個特定的類加載器在接到加載類的請求時,首先將加載任務委托給父類加載器,依次遞歸,如果父類加載器可以完成類加載任務,就成功返回;只有父類加載器無法完成此加載任務時,才自己去加載。

啟動類 - father - 擴展類 - father - 系統類

實例

src 下定義 HelloWorld.java

csu/src/HelloWorld.java 
public class HelloWorld {
    public static void main(String[] args){
        System.out.println("HelloWorld");
    }
}

命令行運行 生成 字節碼文件 HelloWorld.class

ShuaideMacBook-Pro:src shuai$ javac HelloWorld.java 
ShuaideMacBook-Pro:src shuai$ ls
HelloWorld.class    HelloWorld.java

運行字節碼文件 輸出 HelloWorld

ShuaideMacBook-Pro:src shuai$ java HelloWorld
HelloWorld

然后將字節碼文件打成 jar 包,命名為 h.jar

ShuaideMacBook-Pro:src shuai$ jar -cvf h.jar HelloWorld.class
已添加清單
正在添加: HelloWorld.class(輸入 = 419) (輸出 = 285)(壓縮了 31%)

再將 h.jar 移到 擴展類加載器 負責的類庫路徑下 jre/lib/ext

在這之后,改變 HelloWorld.java

public class HelloWorld {
    public static void main(String[] args){
        System.out.println("輸出內容更改");
    }
}

并重新編譯執行

ShuaideMacBook-Pro:src shuai$ javac HelloWorld.java 
ShuaideMacBook-Pro:src shuai$ java HelloWorld
HelloWorld

因為 Java 的雙親委派機制, 擴展類加載器下有相應的 jar 包,所以輸出內容不變。

面試題

能不能自己寫個類叫 java.lang.System ?

答案:通常不可以,但可以采取另類方法達到這個需求。

解釋:為了不讓我們寫System類,類加載采用委托機制,這樣可以保證爸爸們優先,爸爸們能找到的類,兒子就沒有機會加載。而System類是Bootstrap加載器加載的,就算自己重寫,也總是使用Java系統提供的System,自己寫的System類根本沒有機會得到加載。

但是,我們可以自己定義一個類加載器來達到這個目的,為了避免雙親委托機制,這個類加載器也必須是特殊的。由于系統自帶的三個類加載器都加載特定目錄下的類,如果我們自己的類加載器放在一個特殊的目錄,那么系統的加載器就無法加載,也就是最終還是由我們自己的加載器加載。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容