您好,登錄后才能下訂單哦!
本篇文章為大家展示了Java的ClassLoader如何理解,內(nèi)容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
講解一下 Java 的 ClassLoader。
關于 ClassLoader ,相信大家用的不是很多,但是在面試中可能會被經(jīng)常問到。所以我這里整理了關于它的一些相關用法。
ClassLoader 是 Java 提供的類加載器,用來加載 Java 類到 Java 虛擬機中的一種加載器。
Java 程序(class文件)并不是本地的可執(zhí)行程序。當運行Java程序時,首先運行JVM(Java虛擬機),然后再把Java class加載到JVM里頭運行,負責加載Java class的這部分就叫做Class Loader。
JVM本身包含了一個ClassLoader稱為Bootstrap ClassLoader,和JVM一樣,BootstrapClassLoader是用本地代碼實現(xiàn)的,它負責加載核心JavaClass(即所有java.*開頭的類)。另外JVM還會提供兩個ClassLoader,它們都是用Java語言編寫的,由BootstrapClassLoader加載;其中Extension ClassLoader負責加載擴展的Javaclass(例如所有javax.*開頭的類和存放在JRE的ext目錄下的類),ApplicationClassLoader負責加載應用程序自身的類。
當運行一個程序的時候,JVM啟動,運行bootstrapclassloader,該ClassLoader加載java核心API(ExtClassLoader和AppClassLoader也在此時被加載),然后調(diào)用ExtClassLoader加載擴展API,最后AppClassLoader加載CLASSPATH目錄下定義的Class,這就是一個程序最基本的加載流程。
了解了上面的流程后,我們再通過具體的代碼來看看類是如何被加載的。
1 2 3 4 5 6 7 8 9 |
|
運行后,輸出結(jié)果:
1 2 3 |
|
從上面的結(jié)果可以看出,并沒有獲取到 ExtClassLoader 的父 Loader,原因是 Bootstrap Loader(引導類加載器)是用C語言實現(xiàn)的,找不到一個確定的返回父 Loader 的方式,于是就返回 null。 這幾種類加載器的層次關系如下圖所示:
注意:這里父類加載器并不是通過繼承關系來實現(xiàn)的,而是采用組合實現(xiàn)的。
站在Java虛擬機的角度來講,只存在兩種不同的類加載器:啟動類加載器:它使用C++實現(xiàn)(這里僅限于Hotspot,也就是JDK1.5之后默認的虛擬機,有很多其他的虛擬機是用Java語言實現(xiàn)的),是虛擬機自身的一部分;所有其它的類加載器:這些類加載器都由Java語言實現(xiàn),獨立于虛擬機之外,并且全部繼承自抽象類java.lang.ClassLoader
,這些類加載器需要由啟動類加載器加載到內(nèi)存中之后才能去加載其他的類。
站在Java開發(fā)人員的角度來看,類加載器可以大致劃分為以下三類:
啟動類加載器:Bootstrap ClassLoader
,負責加載存放在JDK\jre\lib
(JDK代表JDK的安裝目錄,下同)下,或被-Xbootclasspath
參數(shù)指定的路徑中的,并且能被虛擬機識別的類庫(如rt.jar,所有的java.開頭的類均被Bootstrap ClassLoader
加載)。啟動類加載器是無法被Java程序直接引用的。
擴展類加載器:Extension ClassLoader
,該加載器由sun.misc.Launcher$ExtClassLoader
實現(xiàn),它負責加載JDK\jre\lib\ext
目錄中,或者由java.ext.dirs
系統(tǒng)變量指定的路徑中的所有類庫(如javax.開頭的類),開發(fā)者可以直接使用擴展類加載器。
應用程序類加載器:Application ClassLoader
,該類加載器由sun.misc.Launcher$AppClassLoader
來實現(xiàn),它負責加載用戶類路徑(ClassPath)所指定的類,開發(fā)者可以直接使用該類加載器,如果應用程序中沒有自定義過自己的類加載器,一般情況下這個就是程序中默認的類加載器。
應用程序都是由這三種類加載器互相配合進行加載的,如果有必要,我們還可以加入自定義的類加載器。因為JVM自帶的ClassLoader只是懂得從本地文件系統(tǒng)加載標準的java class文件,因此如果編寫了自己的ClassLoader,便可以做到如下幾點:
1、在執(zhí)行非置信代碼之前,自動驗證數(shù)字簽名。
2、動態(tài)地創(chuàng)建符合用戶特定需要的定制化構(gòu)建類。
3、從特定的場所取得java class,例如數(shù)據(jù)庫中和網(wǎng)絡中。
JVM類加載機制
全盤負責,當一個類加載器負責加載某個Class時,該Class所依賴的和引用的其他Class也將由該類加載器負責載入,除非顯示使用另外一個類加載器來載入
父類委托,先讓父類加載器試圖加載該類,只有在父類加載器無法加載該類時才嘗試從自己的類路徑中加載該類
緩存機制,緩存機制將會保證所有加載過的Class都會被緩存,當程序中需要使用某個Class時,類加載器先從緩存區(qū)尋找該Class,只有緩存區(qū)不存在,系統(tǒng)才會讀取該類對應的二進制數(shù)據(jù),并將其轉(zhuǎn)換成Class對象,存入緩存區(qū)。這就是為什么修改了Class后,必須重啟JVM,程序的修改才會生效
類加載有三種方式:
1、命令行啟動應用時候由JVM初始化加載
2、通過Class.forName()方法動態(tài)加載
3、通過ClassLoader.loadClass()方法動態(tài)加載
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Test2.java
1 2 3 4 5 |
|
分別切換加載方式,會有不同的輸出結(jié)果。
Class.forName()和ClassLoader.loadClass()區(qū)別
Class.forName()
:將類的.class文件加載到jvm中之外,還會對類進行解釋,執(zhí)行類中的static塊;
ClassLoader.loadClass()
:只干一件事情,就是將.class文件加載到jvm中,不會執(zhí)行static中的內(nèi)容,只有在newInstance才會去執(zhí)行static塊。
Class.forName(name, initialize, loader)
帶參函數(shù)也可控制是否加載static塊。并且只有調(diào)用了newInstance()方法采用調(diào)用構(gòu)造函數(shù),創(chuàng)建類的對象 。
總結(jié):Java 類的加載機制和ClassLoader看似復雜,實際上卻很簡單。通過閱讀源碼或結(jié)合運行示例就能更好的理解了。
上述內(nèi)容就是Java的ClassLoader如何理解,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業(yè)資訊頻道。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。