Java三個(gè)類(lèi)加載器及它們的相互關(guān)系
一、什么是類(lèi)加載器?
虛擬機(jī)設(shè)計(jì)團(tuán)隊(duì)把類(lèi)加載階段中的“通過(guò)一個(gè)類(lèi)的全限定名來(lái)獲取描述此類(lèi)的二進(jìn)制字節(jié)流”這個(gè)動(dòng)作放到Java虛擬機(jī)外部去實(shí)現(xiàn),以便讓?xiě)?yīng)用程序自己決定如何去獲取所需要的類(lèi)。實(shí)現(xiàn)這個(gè)動(dòng)作的代碼模塊稱(chēng)為“類(lèi)加載器”
類(lèi)加載器可以說(shuō)是Java語(yǔ)言的一項(xiàng)創(chuàng)新,也是Java語(yǔ)言流行的重要原因之一,它最初是為了滿足Java Applet的需求而開(kāi)發(fā)出來(lái)的。雖然目前Java Applet技術(shù)基本上已經(jīng)“死掉”,但類(lèi)加載器卻在類(lèi)層次劃分、OSGi、熱部署、代碼加密等領(lǐng)域大放異彩,成為了Java技術(shù)體系中一塊重要的基石,可謂是失之桑榆,收之東隅。
類(lèi)加載器雖然只用于實(shí)現(xiàn)類(lèi)的加載動(dòng)作,但它在Java程序中起到的作用卻遠(yuǎn)遠(yuǎn)不限于類(lèi)加載階段。對(duì)于任意一個(gè)類(lèi),都需要由加載它的類(lèi)加載器和這個(gè)類(lèi)本身一同確立其在Java虛擬機(jī)中的唯一性,每一個(gè)類(lèi),都擁有一個(gè)獨(dú)立的類(lèi)名稱(chēng)空間。這句話可以表達(dá)得更通俗一些:比較兩個(gè)類(lèi)是否“相等”,只有在這兩個(gè)類(lèi)是由同一個(gè)類(lèi)加載器加載的前提下才有意義。否則,即使這兩個(gè)類(lèi)來(lái)源于同一個(gè)Class文件,被同一個(gè)虛擬機(jī)加載,只要加載它們的類(lèi)加載器不同,那這兩個(gè)類(lèi)就必定不相等。
二、AppClassLoader系統(tǒng)類(lèi)加載器
AppClassLoader應(yīng)用類(lèi)加載器,又稱(chēng)為系統(tǒng)類(lèi)加載器,負(fù)責(zé)在JVM啟動(dòng)時(shí),加載來(lái)自命令java中的classpath或者java.class.path系統(tǒng)屬性或者CLASSPATH操作系統(tǒng)屬性所指定的JAR類(lèi)包和類(lèi)路徑
- 獲取當(dāng)前類(lèi)的類(lèi)加載器:
public class AppClassLoaderTest {
public static void main(String[] args) {
System.out.println(ClassLoader.getSystemClassLoader());
}
}
輸出:
sun.misc.Launcher$AppClassLoader@73d16e93
這說(shuō)明AppclassLoader是當(dāng)前應(yīng)用classpath所有類(lèi)的加載器。
查看ClassLoader的源碼可發(fā)現(xiàn):在沒(méi)有特定說(shuō)明的情況下,用戶自定義的任何類(lèi)加載器都將該類(lèi)加載器作為自定義類(lèi)加載器的父加載器.
- 通過(guò)執(zhí)行下面的代碼即可獲得classpath的加載路徑:
String classPath = System.getProperty("java.class.path");
for (String path : classPath.split(";")) {
System.out.println(path);
}
輸出:
.
通常是當(dāng)前執(zhí)行字節(jié)碼的路徑。
- main函數(shù)的類(lèi)的加載就是使用AppClassLoader加載器進(jìn)行加載的,而AppClassLoader的父加載器是ExtClassLoader:
public class AppClassLoaderTest {
public static void main(String[] args) {
ClassLoader classLoader = Test.class.getClassLoader();
System.out.println(classLoader);
System.out.println(classLoader.getParent());
}
private static class Test {
}
}
輸出:
sun.misc.Launcher$AppClassLoader@73d16e93
sun.misc.Launcher$ExtClassLoader@15db9742
三、ExtClassLoader擴(kuò)展類(lèi)加載器
ExtClassLoader稱(chēng)為擴(kuò)展類(lèi)加載器,主要負(fù)責(zé)加載Java的擴(kuò)展類(lèi)庫(kù),默認(rèn)加載JAVA_HOME/jre/lib/ext/目錄下的所有jar包或者由java.ext.dirs系統(tǒng)屬性指定的jar包.放入這個(gè)目錄下的jar包對(duì)AppClassLoader加載器都是可見(jiàn)的(因?yàn)镋xtClassLoader是AppClassLoader的父加載器,并且Java類(lèi)加載器采用了委托機(jī)制).
- ExtClassLoader的類(lèi)掃描路徑通過(guò)執(zhí)行下面代碼來(lái)看一下:
public class ExtClassLoaderTest {
public static void main(String[] args) {
String extDirs = System.getProperty("java.ext.dirs");
for (String path : extDirs.split(";")) {
System.out.println(path);
}
}
}
執(zhí)行結(jié)果如下:
D:\TOOLS\JAVA\lib\ext
C:\WINDOWS\Sun\Java\lib\ext
- 從上面的路徑中隨意選擇一個(gè)類(lèi),來(lái)看看它的類(lèi)加載器是什么:
public class ExtClassLoaderTest {
public static void main(String[] args) {
ClassLoader classLoader = sun.security.ec.SunEC.class.getClassLoader();
System.out.println(classLoader);
System.out.println(classLoader.getParent());
}
}
輸出:
sun.misc.Launcher$ExtClassLoader@30f39991
null
從輸出結(jié)果可知ExtClassLoader的父加載器為null
四、BootstrapClassLoader啟動(dòng)類(lèi)加載器
啟動(dòng)類(lèi)加載器,是Java類(lèi)加載層次中最頂層的類(lèi)加載器,負(fù)責(zé)加載JDK中的核心類(lèi)庫(kù),如:rt.jar、resources.jar、charsets.jar等
- 通過(guò)如下程序獲得該類(lèi)加載器從哪些地方加載了相關(guān)的jar或class文件:
import java.net.URL;
public class BootstraplassLoaderPath {
public static void main(String[] args) {
URL[] urLs = sun.misc.Launcher.getBootstrapClassPath().getURLs();
for (URL url : urLs) {
System.out.println(url.toExternalForm());
}
}
}
輸出:
file:/D:/TOOLS/JAVA/lib/resources.jar
file:/D:/TOOLS/JAVA/lib/rt.jar
file:/D:/TOOLS/JAVA/lib/sunrsasign.jar
file:/D:/TOOLS/JAVA/lib/jsse.jar
file:/D:/TOOLS/JAVA/lib/jce.jar
file:/D:/TOOLS/JAVA/lib/charsets.jar
file:/D:/TOOLS/JAVA/lib/jfr.jar
file:/D:/TOOLS/JAVA/classes
- 從rt.jar中選擇String類(lèi),看一下String類(lèi)的類(lèi)加載器是什么:
public class stringBootstraplassLoaderTest {
public static void main(String[] args) {
ClassLoader classLoader = String.class.getClassLoader();
System.out.println(classLoader);
}
}
輸出:
null
由于BootstrapClassLoader對(duì)Java不可見(jiàn),所以返回了null,我們也可以通過(guò)某一個(gè)類(lèi)的加載器是否為null來(lái)作為判斷該類(lèi)是不是使用BootstrapClassLoader進(jìn)行加載的依據(jù)。
另外上面提到ExtClassLoader的父加載器返回的是null,那是否說(shuō)明ExtClassLoader的父加載器是BootstrapClassLoader.
Bootstrap ClassLoader是由C/C++編寫(xiě)的,它本身是虛擬機(jī)的一部分,所以它并不是一個(gè)JAVA類(lèi),也就是無(wú)法在java代碼中獲取它的引用,JVM啟動(dòng)時(shí)通過(guò)Bootstrap類(lèi)加載器加載rt.jar等核心jar包中的class文件,之前的int.class,String.class都是由它加載。
五、加載器關(guān)系總結(jié)
JVM初始化sun.misc.Launcher并創(chuàng)建Extension ClassLoader和AppClassLoader實(shí)例。并將ExtClassLoader設(shè)置為AppClassLoader的父加載器,Bootstrap則是ExtClassLoader的父加載器.
關(guān)系圖如下:

六、參考資料
1.Java類(lèi)加載器
2.一看你就懂,超詳細(xì)java中的ClassLoader詳解
到此這篇關(guān)于Java三個(gè)類(lèi)加載器及它們的相互關(guān)系的文章就介紹到這了,更多相關(guān)Java類(lèi)加載器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- java用類(lèi)加載器的5種方式讀取.properties文件
- Java類(lèi)加載器ClassLoader用法解析
- jvm之java類(lèi)加載機(jī)制和類(lèi)加載器(ClassLoader)的用法
- java類(lèi)加載機(jī)制、類(lèi)加載器、自定義類(lèi)加載器的案例
- 淺談Java自定義類(lèi)加載器及JVM自帶的類(lèi)加載器之間的交互關(guān)系
- Java基礎(chǔ)之自定義類(lèi)加載器
- java?Stream流常見(jiàn)操作方法(反射,類(lèi)加載器,類(lèi)加載,反射)
- Java 類(lèi)加載過(guò)程與類(lèi)加載器詳細(xì)介紹
相關(guān)文章
Springboot之restTemplate配置及使用方式
這篇文章主要介紹了Springboot之restTemplate配置及使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-04-04
詳解Elastic Search搜索引擎在SpringBoot中的實(shí)踐
本篇文章主要介紹了Elastic Search搜索引擎在SpringBoot中的實(shí)踐,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-01-01
一文詳解Spring是怎樣處理循環(huán)依賴(lài)的
循環(huán)依賴(lài)簡(jiǎn)單理解就是A,B 兩個(gè)bean相互依賴(lài),A依賴(lài)B,B依賴(lài)A,A->B、B->A大概就是這樣,這篇文章主要介紹了Spring是怎樣處理循環(huán)依賴(lài)的,文中通過(guò)代碼示例給大家介紹的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下2024-01-01
Redis緩存及熱點(diǎn)key問(wèn)題解決方案
這篇文章主要介紹了Redis緩存及熱點(diǎn)key問(wèn)題解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
java實(shí)現(xiàn)堆的操作方法(建堆,插入,刪除)
下面小編就為大家分享一篇java實(shí)現(xiàn)堆的操作方法(建堆,插入,刪除),具有很好的參考價(jià)值,希望對(duì)大家有所幫助2017-12-12
SWT(JFace)體驗(yàn)之打開(kāi)多個(gè)Form
SWT(JFace)體驗(yàn)之打開(kāi)多個(gè)Form的實(shí)現(xiàn)代碼。2009-06-06

