Java三個(gè)類加載器及它們的相互關(guān)系
一、什么是類加載器?
虛擬機(jī)設(shè)計(jì)團(tuán)隊(duì)把類加載階段中的“通過(guò)一個(gè)類的全限定名來(lái)獲取描述此類的二進(jìn)制字節(jié)流”這個(gè)動(dòng)作放到Java虛擬機(jī)外部去實(shí)現(xiàn),以便讓應(yīng)用程序自己決定如何去獲取所需要的類。實(shí)現(xiàn)這個(gè)動(dòng)作的代碼模塊稱為“類加載器”
類加載器可以說(shuō)是Java語(yǔ)言的一項(xiàng)創(chuàng)新,也是Java語(yǔ)言流行的重要原因之一,它最初是為了滿足Java Applet的需求而開發(fā)出來(lái)的。雖然目前Java Applet技術(shù)基本上已經(jīng)“死掉”,但類加載器卻在類層次劃分、OSGi、熱部署、代碼加密等領(lǐng)域大放異彩,成為了Java技術(shù)體系中一塊重要的基石,可謂是失之桑榆,收之東隅。
類加載器雖然只用于實(shí)現(xiàn)類的加載動(dòng)作,但它在Java程序中起到的作用卻遠(yuǎn)遠(yuǎn)不限于類加載階段。對(duì)于任意一個(gè)類,都需要由加載它的類加載器和這個(gè)類本身一同確立其在Java虛擬機(jī)中的唯一性,每一個(gè)類,都擁有一個(gè)獨(dú)立的類名稱空間。這句話可以表達(dá)得更通俗一些:比較兩個(gè)類是否“相等”,只有在這兩個(gè)類是由同一個(gè)類加載器加載的前提下才有意義。否則,即使這兩個(gè)類來(lái)源于同一個(gè)Class文件,被同一個(gè)虛擬機(jī)加載,只要加載它們的類加載器不同,那這兩個(gè)類就必定不相等。
二、AppClassLoader系統(tǒng)類加載器
AppClassLoader應(yīng)用類加載器,又稱為系統(tǒng)類加載器,負(fù)責(zé)在JVM啟動(dòng)時(shí),加載來(lái)自命令java中的classpath或者java.class.path系統(tǒng)屬性或者CLASSPATH操作系統(tǒng)屬性所指定的JAR類包和類路徑
- 獲取當(dāng)前類的類加載器:
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所有類的加載器。
查看ClassLoader的源碼可發(fā)現(xiàn):在沒(méi)有特定說(shuō)明的情況下,用戶自定義的任何類加載器都將該類加載器作為自定義類加載器的父加載器.
- 通過(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ù)的類的加載就是使用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ò)展類加載器
ExtClassLoader稱為擴(kuò)展類加載器,主要負(fù)責(zé)加載Java的擴(kuò)展類庫(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類加載器采用了委托機(jī)制).
- ExtClassLoader的類掃描路徑通過(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)看看它的類加載器是什么:
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)類加載器
啟動(dòng)類加載器,是Java類加載層次中最頂層的類加載器,負(fù)責(zé)加載JDK中的核心類庫(kù),如:rt.jar、resources.jar、charsets.jar等
- 通過(guò)如下程序獲得該類加載器從哪些地方加載了相關(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類,看一下String類的類加載器是什么:
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è)類的加載器是否為null來(lái)作為判斷該類是不是使用BootstrapClassLoader進(jìn)行加載的依據(jù)。
另外上面提到ExtClassLoader的父加載器返回的是null,那是否說(shuō)明ExtClassLoader的父加載器是BootstrapClassLoader.
Bootstrap ClassLoader是由C/C++編寫的,它本身是虛擬機(jī)的一部分,所以它并不是一個(gè)JAVA類,也就是無(wú)法在java代碼中獲取它的引用,JVM啟動(dòng)時(shí)通過(guò)Bootstrap類加載器加載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類加載器
2.一看你就懂,超詳細(xì)java中的ClassLoader詳解
到此這篇關(guān)于Java三個(gè)類加載器及它們的相互關(guān)系的文章就介紹到這了,更多相關(guān)Java類加載器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java 入門圖形用戶界面設(shè)計(jì)之列表框JList
圖形界面(簡(jiǎn)稱GUI)是指采用圖形方式顯示的計(jì)算機(jī)操作用戶界面。與早期計(jì)算機(jī)使用的命令行界面相比,圖形界面對(duì)于用戶來(lái)說(shuō)在視覺(jué)上更易于接受,本篇精講Java語(yǔ)言中關(guān)于圖形用戶界面的列表框JList2022-02-02Java數(shù)據(jù)結(jié)構(gòu)之堆(優(yōu)先隊(duì)列)的實(shí)現(xiàn)
堆(優(yōu)先隊(duì)列)是一種典型的數(shù)據(jù)結(jié)構(gòu),其形狀是一棵完全二叉樹,一般用于求解topk問(wèn)題。本文將利用Java語(yǔ)言實(shí)現(xiàn)堆,感興趣的可以學(xué)習(xí)一下2022-05-05一次mybatis連接查詢遇到的坑實(shí)戰(zhàn)記錄
這篇文章主要給大家介紹了關(guān)于一次mybatis連接查詢遇到的坑的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12JAVA進(jìn)階之HashMap底層實(shí)現(xiàn)解析
Hashmap是java面試中經(jīng)常遇到的面試題,大部分都會(huì)問(wèn)其底層原理與實(shí)現(xiàn),為了能夠溫故而知新,特地寫了這篇文章,以便時(shí)時(shí)學(xué)習(xí)2021-11-11Java數(shù)組,去掉重復(fù)值、增加、刪除數(shù)組元素的方法
下面小編就為大家?guī)?lái)一篇Java數(shù)組,去掉重復(fù)值、增加、刪除數(shù)組元素的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-10-10詳解java平臺(tái)解析協(xié)議相關(guān)備忘
這篇文章主要介紹了詳解java平臺(tái)解析協(xié)議相關(guān)備忘,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01Java的內(nèi)存區(qū)域與內(nèi)存溢出異常你了解嗎
這篇文章主要為大家詳細(xì)介紹了Java的內(nèi)存區(qū)域與內(nèi)存溢出異常,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-03-03Mybatis數(shù)據(jù)批量插入如何實(shí)現(xiàn)
這篇文章主要介紹了Mybatis數(shù)據(jù)批量插入如何實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07