天天看點

JVM(10)——類加載器與雙親委派模型

類加載器

對于任意一個類,都需要由加載它的類加載器和這個類本身一同确立其在Java虛拟機中的唯一性。這句話表達得更通俗一些就是:比較兩個類是否“相等”,隻有在這兩個類是由同一個類加載器加載地前提下才有意義,否則,即使這兩個類來源于同一個class檔案,隻有加載它們地類加載器不同,那這兩個類就必定不相等。

雙親委派模型

站在Java虛拟機的角度,隻存在兩種不同地類加載器:一種是啟動類加載器,這個類加載器使用C++語言實作,是虛拟機自身的一部分;另一種是所有其他的類加載器,這個類加載器都由Java語言實作,獨立于虛拟機外部,并且全部繼承自抽象類

java.lang.ClassLoader

從Java開發人員的角度來看,類加載器就還可以劃分得更細緻一些,絕大部分Java程式都會使用到一下三種系統提供的類加載器:

  • 啟動類加載器:這個類加載器負責将存放在

    <JAVA_HOME>\lib

    目錄中,或者被

    -Xboootclasspath

    參數所指定的路徑中的,并且是虛拟機識别類庫加載到虛拟機記憶體中。啟動類加載器無法被Java程式直接引用
  • 擴充類加載器:這個加載器由

    sum.misc.Launcher$ExtClassLoader

    實作,它負責加載

    <JAVA_HONE>\lib\ext

    目錄中的,或者被

    java.ext.dirs

    系統變量所指定的路徑中的所有類庫,開發者可以直接使用擴充類加載器。
  • 應用程式類加載器:這個類加載器由

    sum.misc.Launcher$AppClassLoader

    來實作。由于這個類加載器是

    ClassLoader

    中的

    getSystemClassLoader()

    方法的傳回值,是以一般也稱它為系統類加載器。它負責加載使用者類路徑上所制定的類庫,開發者可以直接使用這個類加載器,如果應用程式中沒有自定義過自己的類加載器,一般情況下這個就是程式中預設的類加載器。
JVM(10)——類加載器與雙親委派模型

圖中展示的類加載器之間的這種層次關系,就稱為類加載器的雙親委派模型。雙親委派模型要求除了頂層的啟動類加載器外,其餘的類加載器都應當有自己的父類加載器。

雙親委派模型的工作過程

如果一個類加載器收到了類加載的請求,它首先不會自己去嘗試加載這個類,而是把這個i請求委派給父親加載器去完成,每一個層次的類加載器都是如此,是以所有的加載請求最終都應該傳送到頂層的啟動類加載器中,隻有當附加在其回報自己無法完成這個加載請求(它的搜尋範圍中沒有找到所需的類)時,子加載器才會嘗試自己去加載。

為什麼使用雙親委派模型

使用雙親委派模型來組織類加載器之間的關系,有一個顯而易見的好處是Java類随着它的類加載器一起具備了一種帶有優先級的層次關系。例如類

java.lang.Object

,它存放在

rt.jar

中,無論哪一個類加載器要加載這個類,最終都是委派給啟動類加載器進行加載,是以Object類在程式的各種類加載器環境中都是同一個類。相反,如果沒有使用雙親委派模型,由各個類加載器自行去加載的話,如果使用者自己寫一個名為

java.lang.Object

的類,并放在程式的ClassPath中,那徐彤中将會出現多個不同的Object類,Java類型體系中最基礎的行為也就無從保證,應用程式也将會變得一片混亂。