1. 程式人生 > >jvm:類載入器與雙親委派模型

jvm:類載入器與雙親委派模型

兩個類相等需要類本身相等,並且使用同一個類載入器進行載入。這是因為每一個類載入器都擁有一個獨立的類名稱空間。

這裡的相等,包括類的 Class 物件的 equals() 方法、isAssignableFrom() 方法、isInstance() 方法的返回結果為 true,也包括使用 instanceof 關鍵字做物件所屬關係判定結果為 true。

類載入器分類

從 Java 虛擬機器的角度來講,只存在以下兩種不同的類載入器:

  • 啟動類載入器(Bootstrap ClassLoader),這個類載入器用 C++ 實現,是虛擬機器自身的一部分;

  • 所有其他類的載入器,這些類由 Java 實現,獨立於虛擬機器外部,並且全都繼承自抽象類 java.lang.ClassLoader。

從 Java 開發人員的角度看,類載入器可以劃分得更細緻一些:

  • 啟動類載入器(Bootstrap ClassLoader)此類載入器負責將存放在 <JRE_HOME>\lib 目錄中的,或者被 -Xbootclasspath 引數所指定的路徑中的,並且是虛擬機器識別的(僅按照檔名識別,如 rt.jar,名字不符合的類庫即使放在 lib 目錄中也不會被載入)類庫載入到虛擬機器記憶體中。啟動類載入器無法被 Java 程式直接引用,使用者在編寫自定義類載入器時,如果需要把載入請求委派給啟動類載入器,直接使用 null 代替即可。

  • 擴充套件類載入器(Extension ClassLoader)這個類載入器是由 ExtClassLoader(sun.misc.Launcher$ExtClassLoader)實現的。它負責將 <JAVA_HOME>/lib/ext 或者被 java.ext.dir 系統變數所指定路徑中的所有類庫載入到記憶體中,開發者可以直接使用擴充套件類載入器。

  • 應用程式類載入器(Application ClassLoader)這個類載入器是由 AppClassLoader(sun.misc.Launcher$AppClassLoader)實現的。由於這個類載入器是 ClassLoader 中的 getSystemClassLoader() 方法的返回值,因此一般稱為系統類載入器。它負責載入使用者類路徑(ClassPath)上所指定的類庫,開發者可以直接使用這個類載入器,如果應用程式中沒有自定義過自己的類載入器,一般情況下這個就是程式中預設的類載入器。

雙親委派模型

應用程式都是由三種類載入器相互配合進行載入的,如果有必要,還可以加入自己定義的類載入器。

下圖展示的類載入器之間的層次關係,稱為類載入器的雙親委派模型(Parents Delegation Model)。該模型要求除了頂層的啟動類載入器外,其餘的類載入器都應有自己的父類載入器。這裡類載入器之間的父子關係一般通過組合(Composition)關係來實現,而不是通過繼承(Inheritance)的關係實現。

 

1. 工作過程

一個類載入器首先將類載入請求傳送到父類載入器,只有當父類載入器無法完成類載入請求時才嘗試載入。

2. 好處

使得 Java 類隨著它的類載入器一起具有一種帶有優先順序的層次關係,從而使得基礎類得到統一。

優先順序:通過啟動類載入器載入的類 > 擴充套件類載入器載入的類 > 應用程式載入器載入的類

例如 java.lang.Object 存放在 rt.jar 中,如果編寫另外一個 java.lang.Object 的類並放到 ClassPath 中,程式可以編譯通過。由於雙親委派模型的存在,所以在 rt.jar 中的 Object 比在 ClassPath 中的 Object 優先順序更高這是因為 rt.jar 中的 Object 使用的是啟動類載入器,而 ClassPath 中的 Object 使用的是應用程式類載入器。rt.jar 中的 Object 優先順序更高,因此在各種類載入器環境中都是同一個類。

每一個類,都需要由載入它的類載入器和類本身來確定其在JVM中的唯一性