天天看點

Java-類加載器和雙親委派機制

java中一個類是如何被虛拟機加載的呢?下面我們來介紹一下類加載器和雙親委派機制。

類加載器(ClassLoader)

"通過一個類的全限定名來擷取描述此類的二進制位元組流"這個動作是在JVM外部來實作的,以便讓應用程式自己決定如何擷取所需的類.實作這個動作的代碼子產品就稱為類加載器.

ClassLoader隻負責加載class檔案,class檔案在檔案的開頭都有特定的檔案辨別,至于它是否可以運作,則由Execution Engine決定.

類加載器結構
Java-類加載器和雙親委派機制

類加載器種類

類加載器分為虛拟機自帶的加載器(前3種)和使用者自定義的加載器(第4種)

1.啟動類加載器(BootstrapClassLoader)

負責加載%JAVA_HOME%\lib下的rt.jar、charsets.jar和class等,或者是-Xbootclasspath參數指定的路徑.根類加載器可以了解成一個概念上的東西,因為我們無法通過Java代碼擷取根類加載器,它屬于JVM層面.

2.擴充類加載器(ExtClassLoader)

該類是sun.misc.Launcher的一個内部類.負責加載%JAVA_HOME%\lib\ext目錄下的所有jar包和class檔案,或者是java.ext.dirs參數指定的路徑.

3.應用程式類加載器(AppClassLoader)

該類是sun.misc.Launcher的一個内部類.負責加載使用者類路徑上所指定的類庫(主要負責加載應用程式的主函數類),如果應用程式中沒有自定義加載器,那麼類加載器就為預設加載器.

4.使用者自定義的加載器

需要繼承ClassLoader抽象類

說明:

擴充類加載器和應用類加載器都是通過類sun.misc.Launcher進行初始化,而Launcher類則由根類加載器進行加載.

雙親委派機制

虛拟機是根據類的全限定名來加載類的,那麼有個問題,如果同時存在兩個或多個全限定名完全一緻的情況下.如何選擇加載哪個類.這就是雙親委派機制要做的工作.

雙親委派機制的原理

雙親委派模型是指當我們調用類加載器的loadClass()進行類加載時,該類加載器會首先請求它的父類加載器進行加載,依次遞歸.如果所有父類加載器都加載失敗,則目前類加載器自己進行加載操作.

1-類加載器收到類加載的請求;

2-把這個請求委托給父加載器去完成,一直向上委托直到啟動類加載器;

3-啟動器加載器檢查能不能加載(使用findClass()方法),能就加載(結束);否則,抛出異常,通知子加載器進行加載.

4-重複步驟三.

說明:

當一個HelloWorld.class檔案被加載時.不考慮自定義類加載器,首先會在AppClassLoader中檢查是否已加載過,如果有就無需再加載.如果沒有,那麼會拿到父加載器,然後調用父加載器的loadClass().父類中同樣會先檢查自己是否已經加載過,如果沒有再往上.直到到達BootstrapClassLoader之前,都是沒有哪個加載器自己選擇加載的.如果父加載器無法加載,會下沉到子加載器去加載,一直到最底層,如果沒有任何加載器能加載,就會抛出ClassNotFoundException.

雙親委派機制設計的優點

1:安全,可避免使用者自己編寫的類動态替換Java的核心類,如java.lang.String

2:避免全限定命名的類重複加載(使用了findLoadClass()判斷目前類是否已加載)

這種設計有個好處是,如果有人想替換系統級别的類:String.在雙親委派機制下這些系統類已經被Bootstrap classLoader加載過了,不會再去加載,從一定程度上防止了危險代碼的植入.

注意:

1.ClassLoader類是一個抽象類,但沒有包含任何抽象方法.

2.如果要實作自己的類加載器且不破壞雙親委派模型,隻需繼承ClassLoader類并重寫findClass().

3.如果要實作自己的類加載器且破壞雙親委派模型,則需繼承ClassLoader類并重寫loadClass()、findClass().