日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
這一篇文章,可以把Java中的類(lèi)加載器了解的七七八八了

本文轉(zhuǎn)載自微信公眾號(hào)「程序新視界」,作者丑胖俠二師兄。轉(zhuǎn)載本文請(qǐng)聯(lián)系程序新視界公眾號(hào)。

成都創(chuàng)新互聯(lián)公司專(zhuān)注于南陽(yáng)網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠(chéng)為您提供南陽(yáng)營(yíng)銷(xiāo)型網(wǎng)站建設(shè),南陽(yáng)網(wǎng)站制作、南陽(yáng)網(wǎng)頁(yè)設(shè)計(jì)、南陽(yáng)網(wǎng)站官網(wǎng)定制、微信小程序定制開(kāi)發(fā)服務(wù),打造南陽(yáng)網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供南陽(yáng)網(wǎng)站排名全網(wǎng)營(yíng)銷(xiāo)落地服務(wù)。

前言

對(duì)于每個(gè)開(kāi)發(fā)人員來(lái)說(shuō),java.lang.ClassNotFoundExcetpion這個(gè)異常幾乎都遇到過(guò),而追求其該異常的來(lái)源的話(huà),就免不了談一談Java的類(lèi)加載器了。本文就基于啟動(dòng)類(lèi)加載器、擴(kuò)展類(lèi)加載器、系統(tǒng)類(lèi)加載器和自定義類(lèi)加載器來(lái)為大家補(bǔ)充一下這方面的知識(shí)。

類(lèi)加載器簡(jiǎn)介

Java程序被編譯器編譯之后成為字節(jié)碼文件(.class文件),當(dāng)程序需要某個(gè)類(lèi)時(shí),虛擬機(jī)便會(huì)將對(duì)應(yīng)的class文件進(jìn)行加載,創(chuàng)建出對(duì)應(yīng)的Class對(duì)象。而這個(gè)將class文件加載到虛擬機(jī)內(nèi)存的過(guò)程,便是類(lèi)加載。

類(lèi)加載器負(fù)責(zé)在運(yùn)行時(shí)將Java類(lèi)動(dòng)態(tài)加載到JVM(Java虛擬機(jī)),是JRE(Java運(yùn)行時(shí)環(huán)境)的一部分。由于類(lèi)加載器的存在,JVM無(wú)需了解底層文件或文件系統(tǒng)即可運(yùn)行Java程序。

Java類(lèi)不會(huì)一次全部加載到內(nèi)存中,而是在應(yīng)用程序需要時(shí)才會(huì)加載。此時(shí),類(lèi)加載器負(fù)責(zé)將類(lèi)加載到內(nèi)存中。

類(lèi)加載的過(guò)程

類(lèi)的生命周期通常包括:加載、鏈接、初始化、使用和卸載。上圖中包含了類(lèi)加載的三個(gè)階段:加載階段、鏈接階段和初始化階段。如果將這三個(gè)階段再拆分細(xì)化包括:加載、驗(yàn)證、準(zhǔn)備、解析和初始化。

關(guān)于這幾個(gè)階段的作用,已經(jīng)有很多文章在寫(xiě)了,我們就簡(jiǎn)單概況一下:

  • 加載:通過(guò)一個(gè)類(lèi)的完全限定查找類(lèi)字節(jié)碼文件,轉(zhuǎn)化為方法區(qū)運(yùn)行時(shí)的數(shù)據(jù)結(jié)構(gòu),創(chuàng)建一個(gè)代表該類(lèi)的Class對(duì)象。
  • 驗(yàn)證:確保Class文件的字節(jié)流中包含信息符合當(dāng)前虛擬機(jī)要求,不會(huì)危害虛擬機(jī)自身安全。
  • 準(zhǔn)備:為類(lèi)變量(即static修飾的字段變量)分配內(nèi)存并且設(shè)置該類(lèi)變量的初始值。不包含被final修飾的static變量,因?yàn)樗诰幾g時(shí)已經(jīng)分配了。
  • 解析:將常量池內(nèi)的符號(hào)引用轉(zhuǎn)換為直接引用的過(guò)程。如果符號(hào)引用指向一個(gè)未被加載的類(lèi),或者未被加載類(lèi)的字段或方法,那么解析將觸發(fā)這個(gè)類(lèi)的加載。
  • 初始化:類(lèi)加載最后階段,若該類(lèi)具有超類(lèi),則對(duì)其進(jìn)行初始化,執(zhí)行靜態(tài)初始化器和靜態(tài)初始化成員變量。

在上述類(lèi)加載的過(guò)程中,虛擬機(jī)內(nèi)部提供了三種類(lèi)加載器:?jiǎn)?dòng)(Bootstrap)類(lèi)加載器、擴(kuò)展(Extension)類(lèi)加載器、系統(tǒng)(System)類(lèi)加載器(也稱(chēng)應(yīng)用類(lèi)加載器)。

下面就討論不同類(lèi)型的內(nèi)置類(lèi)加載器是如何工作,以及介紹如何自定義類(lèi)加載器。

內(nèi)置類(lèi)加載器

先從一個(gè)簡(jiǎn)單的例子來(lái)看一下如何使用不同的加載器來(lái)加載不同的類(lèi):

 
 
 
 
  1. public void printClassLoaders() {
  2.     System.out.println("Classloader of this class:"
  3.         + PrintClassLoader.class.getClassLoader());
  4.     System.out.println("Classloader of Logging:"
  5.         + Logging.class.getClassLoader());
  6.     System.out.println("Classloader of ArrayList:"
  7.         + ArrayList.class.getClassLoader());
  8. }

執(zhí)行上述程序,打印如下內(nèi)容:

 
 
 
 
  1. Classloader of this class:sun.misc.Launcher$AppClassLoader@18b4aac2
  2. Classloader of Logging:sun.misc.Launcher$ExtClassLoader@2f0e140b
  3. Classloader of ArrayList:null

上述三行輸出分別對(duì)應(yīng)三種不同的類(lèi)加載器:系統(tǒng)(System)類(lèi)加載器、擴(kuò)展(Extension)類(lèi)加載器和啟動(dòng)(Bootstrap)類(lèi)加載器(顯示為null)。

系統(tǒng)程序類(lèi)加載器加載包含示例方法的類(lèi),也就是將我們自己的文件加載到類(lèi)路徑中。擴(kuò)展類(lèi)加載器加載Logging類(lèi),也就是加載作為標(biāo)準(zhǔn)核心Java類(lèi)擴(kuò)展的類(lèi)。啟動(dòng)類(lèi)加載器加載ArrayList類(lèi),是所有其他類(lèi)的父級(jí)。

對(duì)于ArrayList的類(lèi)加載器,輸出為null。這是因?yàn)閱?dòng)類(lèi)加載器是用本機(jī)代碼實(shí)現(xiàn)而不是Java,因此它不會(huì)顯示為Java類(lèi)。啟動(dòng)類(lèi)加載器在操作在不同的JVM中會(huì)有所不同。

上述三種類(lèi)加載器,外加自定義類(lèi)加載器,它們直接的關(guān)系可用下圖表示:

現(xiàn)在來(lái)具體看一下這些類(lèi)加載器。

Bootstrap類(lèi)加載器

Java類(lèi)由java.lang.ClassLoader的實(shí)例加載。但是,類(lèi)加載器本身就是類(lèi)。那么,誰(shuí)來(lái)加載java.lang.ClassLoader?對(duì),就是啟動(dòng)類(lèi)加載器。

啟動(dòng)類(lèi)加載器主要負(fù)責(zé)加載JDK內(nèi)部類(lèi),通常是rt.jar和$JAVA_HOME/jre/lib目錄中的其他核心庫(kù)。此外,Bootstrap類(lèi)加載器還充當(dāng)所有其他ClassLoader實(shí)例的父類(lèi)。

該啟動(dòng)程序類(lèi)加載器是Java虛擬機(jī)的一部分,用本機(jī)代碼編寫(xiě)(比如,C++),不同的平臺(tái)的實(shí)現(xiàn)可能有所不同。

出于安全考慮,Bootstrap啟動(dòng)類(lèi)加載器只加載包名為java、javax、sun等開(kāi)頭的類(lèi)。

Extension類(lèi)加載器

擴(kuò)展類(lèi)加載器是啟動(dòng)類(lèi)加載器的子類(lèi),Java語(yǔ)言編寫(xiě),由sun.misc.Launcher$ExtClassLoader實(shí)現(xiàn),父類(lèi)加載器為啟動(dòng)類(lèi)加載器,負(fù)責(zé)加載標(biāo)準(zhǔn)核心Java類(lèi)的擴(kuò)展。

擴(kuò)展類(lèi)加載器從JDK擴(kuò)展目錄(通常是$JAVA_HOME/lib/ext目錄)或java.ext.dirs系統(tǒng)屬性中指定的任何其他目錄進(jìn)行自動(dòng)加載。

系統(tǒng)類(lèi)加載器

系統(tǒng)類(lèi)加載器負(fù)責(zé)將所有應(yīng)用程序級(jí)類(lèi)加載到JVM中。它加載在類(lèi)路徑環(huán)境變量,-classpath或-cp命令行選項(xiàng)中找到的文件。它是擴(kuò)展類(lèi)加載器的子類(lèi)。

系統(tǒng)類(lèi)加載器,也稱(chēng)應(yīng)用程序加載器是指 Sun公司實(shí)現(xiàn)的sun.misc.Launcher$AppClassLoader,負(fù)責(zé)加載系統(tǒng)類(lèi)路徑-classpath或-D java.class.path指定路徑下的類(lèi)庫(kù),也就是我們經(jīng)常用到的classpath路徑,開(kāi)發(fā)者可以直接使用系統(tǒng)類(lèi)加載器,一般情況下該類(lèi)加載是程序中默認(rèn)的類(lèi)加載器,通過(guò)ClassLoader#getSystemClassLoader()方法可以獲取到該類(lèi)加載器。

類(lèi)加載器是如何工作的

類(lèi)加載器是Java運(yùn)行時(shí)環(huán)境的一部分。當(dāng)JVM請(qǐng)求一個(gè)類(lèi)時(shí),類(lèi)加載器將嘗試定位該類(lèi),并使用完全限定名將類(lèi)定義裝入運(yùn)行時(shí)。

java.lang.ClassLoader.loadClass()方法負(fù)責(zé)將類(lèi)定義加載到運(yùn)行時(shí),它嘗試通過(guò)全限定名來(lái)加載類(lèi)。如果未加載到該類(lèi),則它將請(qǐng)求委派給父類(lèi)加載器。依次向上重復(fù)該過(guò)程。

最終,如果父類(lèi)加載器找不到指定類(lèi),則子類(lèi)將調(diào)用java.net.URLClassLoader.findClass()方法在文件系統(tǒng)本身中查找類(lèi)。

如果最后一個(gè)子類(lèi)加載器也無(wú)法加載該類(lèi),則它將拋出java.lang.NoClassDefFoundError或java.lang.ClassNotFoundException。拋出ClassNotFoundException時(shí)的輸出示例:

 
 
 
 
  1. java.lang.ClassNotFoundException: com.baeldung.classloader.SampleClassLoader    
  2.     at java.net.URLClassLoader.findClass(URLClassLoader.java:381)    
  3.     at java.lang.ClassLoader.loadClass(ClassLoader.java:424)    
  4.     at java.lang.ClassLoader.loadClass(ClassLoader.java:357)    
  5.     at java.lang.Class.forName0(Native Method)    
  6.     at java.lang.Class.forName(Class.java:348)

上述過(guò)程,通常我們稱(chēng)作雙親委派機(jī)制。雙親委派機(jī)制要求除了頂層的啟動(dòng)類(lèi)加載器外,其余的類(lèi)加載器都應(yīng)當(dāng)有自己的父類(lèi)加載器,請(qǐng)注意雙親委派機(jī)制中的父子關(guān)系并非通常所說(shuō)的類(lèi)繼承關(guān)系,而是采用組合關(guān)系來(lái)復(fù)用父類(lèi)加載器的相關(guān)代碼。

除外,類(lèi)加載器還具有三個(gè)重要功能:委派模型、類(lèi)的唯一性和可見(jiàn)性。

委派模型

類(lèi)加載器遵循委派模型,在該模型中,根據(jù)請(qǐng)求查找類(lèi)或資源,ClassLoader實(shí)例會(huì)將對(duì)類(lèi)或資源的搜索委托給父類(lèi)加載器。

假設(shè)我們有一個(gè)將應(yīng)用程序類(lèi)加載到JVM中的請(qǐng)求。系統(tǒng)類(lèi)加載器首先將該類(lèi)的加載委托給其父擴(kuò)展類(lèi)加載器,而父擴(kuò)展類(lèi)加載器又將其委托給引導(dǎo)類(lèi)加載器。

僅當(dāng)啟動(dòng)類(lèi)加載器和擴(kuò)展類(lèi)加載器都未能成功加載類(lèi)時(shí),系統(tǒng)類(lèi)加載器才會(huì)嘗試加載類(lèi)本身。

類(lèi)的唯一性

作為委托模型的結(jié)果,很容易確保類(lèi)的唯一性,因?yàn)槭冀K嘗試向上委托。如果父類(lèi)加載器無(wú)法找到該類(lèi),則只有當(dāng)前實(shí)例自己會(huì)嘗試進(jìn)行查找和加載。

可見(jiàn)性

此外,子類(lèi)加載器對(duì)其父類(lèi)加載器加載的類(lèi)可見(jiàn)。例如,系統(tǒng)類(lèi)加載器加載的類(lèi)對(duì)擴(kuò)展和Bootstrap類(lèi)加載器加載的類(lèi)具有可見(jiàn)性,反之亦然。

比如,通過(guò)系統(tǒng)類(lèi)加載器加載類(lèi)A,而通過(guò)擴(kuò)展類(lèi)加載器加載類(lèi)B,則對(duì)系統(tǒng)類(lèi)加載器加載的其他類(lèi)而言,A和B類(lèi)都是可見(jiàn)的。但對(duì)擴(kuò)展類(lèi)加載器加載的其他類(lèi)而言,類(lèi)B是唯一可見(jiàn)的類(lèi)。

自定義類(lèi)加載器

在大多數(shù)情況下,如果文件已經(jīng)在文件系統(tǒng)中,則內(nèi)置的類(lèi)加載器就足夠了。但是,在需要從本地硬盤(pán)驅(qū)動(dòng)器或網(wǎng)絡(luò)中加載類(lèi)的情況下,可能需要使用自定義類(lèi)加載器。下面介紹自定義類(lèi)加載器的使用。

自定義類(lèi)加載器示例

自定義類(lèi)加載器不僅對(duì)在運(yùn)行時(shí)加載類(lèi)有幫助,還有一些特殊的場(chǎng)景:

  • 幫助修改現(xiàn)有的字節(jié)碼,例如weaving agents;
  • 動(dòng)態(tài)創(chuàng)建適合用戶(hù)需求的類(lèi)。例如在JDBC中,通過(guò)動(dòng)態(tài)類(lèi)加載完成不同驅(qū)動(dòng)程序?qū)崿F(xiàn)之間的切換。
  • 在為具有相同名稱(chēng)和程序包的類(lèi)加載不同的字節(jié)碼時(shí),實(shí)現(xiàn)類(lèi)版本控制機(jī)制。這可以通過(guò)URL類(lèi)加載器(通過(guò)URL加載jar)或自定義類(lèi)加載器來(lái)完成。

舉一個(gè)更具體的例子,比如,瀏覽器使用自定義類(lèi)加載器從網(wǎng)站加載可執(zhí)行內(nèi)容。瀏覽器可以使用單獨(dú)的類(lèi)加載器從不同的網(wǎng)頁(yè)加載applet。用于運(yùn)行applet的applet查看器包含一個(gè)ClassLoader,該類(lèi)加載器可訪問(wèn)遠(yuǎn)程服務(wù)器上的網(wǎng)站,而無(wú)需查看本地文件系統(tǒng)。

然后通過(guò)HTTP加載原始字節(jié)碼文件,并將其轉(zhuǎn)換為JVM中的類(lèi)。即使這些applet具有相同的名稱(chēng),但如果由不同的類(lèi)加載器加載,它們也被視為不同的組件。

現(xiàn)在,我們了解了為什么自定義類(lèi)加載器是相關(guān)的,讓我們實(shí)現(xiàn)ClassLoader的子類(lèi)來(lái)擴(kuò)展和總結(jié)JVM如何加載類(lèi)的。

創(chuàng)建自定義類(lèi)加載器

自定義類(lèi)加載器通常通過(guò)繼承java.lang.ClassLoader類(lèi),重寫(xiě)findClass()方法:

 
 
 
 
  1. public class CustomClassLoader extends ClassLoader {
  2.     @Override
  3.     public Class findClass(String name) throws ClassNotFoundException {
  4.         byte[] b = loadClassFromFile(name);
  5.         return defineClass(name, b, 0, b.length);
  6.     }
  7.     private byte[] loadClassFromFile(String fileName)  {
  8.         InputStream inputStream = getClass().getClassLoader().getResourceAsStream(
  9.                 fileName.replace('.', File.separatorChar) + ".class");
  10.         byte[] buffer;
  11.         ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
  12.         int nextValue = 0;
  13.         try {
  14.             while ( (nextValue = inputStream.read()) != -1 ) {
  15.                 byteStream.write(nextValue);
  16.             }
  17.         } catch (IOException e) {
  18.             e.printStackTrace();
  19.         }
  20.         buffer = byteStream.toByteArray();
  21.         return buffer;
  22.     }
  23. }

在上面的示例中,我們定義了一個(gè)自定義類(lèi)加載器,該類(lèi)加載器擴(kuò)展了默認(rèn)類(lèi)加載器并從指定文件加載字節(jié)數(shù)組。如果沒(méi)有太復(fù)雜的需求,可以直接繼承URLClassLoader類(lèi),重寫(xiě)loadClass方法,具體可參考AppClassLoader和ExtClassLoader。

了解java.lang.ClassLoader

下面來(lái)看看java.lang.ClassLoader類(lèi)中的一些基本方法,以更清楚地了解其工作方式。

loadClass方法

 
 
 
 
  1. public Class loadClass(String name, boolean resolve) throws ClassNotFoundException {

此方法負(fù)責(zé)加載給定名稱(chēng)參數(shù)的類(lèi)。name參數(shù)為類(lèi)的全限定名。

Java虛擬機(jī)調(diào)用loadClass()方法來(lái)解析類(lèi)引用,并將resolve設(shè)置為true。但是,不一定總是要解析一個(gè)類(lèi)。如果只需要確定該類(lèi)是否存在,則將resolve參數(shù)設(shè)置為false。

此方法用作類(lèi)加載器的入口。我們可以嘗試從java.lang.ClassLoader的源代碼中了解loadClass()方法的內(nèi)部工作:

 
 
 
 
  1. protected Class loadClass(String name, boolean resolve)
  2.   throws ClassNotFoundException {
  3.     
  4.     synchronized (getClassLoadingLock(name)) {
  5.         // First, check if the class has already been loaded
  6.         Class c = findLoadedClass(name);
  7.         if (c == null) {
  8.             long t0 = System.nanoTime();
  9.                 try {
  10.                     if (parent != null) {
  11.                         c = parent.loadClass(name, false);
  12.                     } else {
  13.                         c = findBootstrapClassOrNull(name);
  14.                     }
  15.                 } catch (ClassNotFoundException e) {
  16.                     // ClassNotFoundException thrown if class not found
  17.                     // from the non-null parent class loader
  18.                 }
  19.                 if (c == null) {
  20.                     // If still not found, then invoke findClass in order
  21.                     // to find the class.
  22.                     c = findClass(name);
  23.                 }
  24.             }
  25.             if (resolve) {
  26.                 resolveClass(c);
  27.             }
  28.             return c;
  29.         }
  30.     }

該方法的默認(rèn)實(shí)現(xiàn)按以下順序搜索類(lèi):

  • 調(diào)用findLoadedClass(String)方法以查看是否已加載該類(lèi)。
  • 在父類(lèi)加載器上調(diào)用loadClass(String)方法。
  • 調(diào)用findClass(String)方法以查找類(lèi)。

defineClass方法

 
 
 
 
  1. protected final Class defineClass(
  2. String name, byte[] b, int off, int len) throws ClassFormatError

此方法負(fù)責(zé)將字節(jié)數(shù)組轉(zhuǎn)換為類(lèi)的實(shí)例。如果數(shù)據(jù)不包含有效的類(lèi),則會(huì)拋出ClassFormatError。另外,由于此方法被標(biāo)記為final,因此我們無(wú)法覆蓋此方法。

findClass方法

 
 
 
 
  1. protected Class findClass(
  2.   String name) throws ClassNotFoundException

此方法查找以標(biāo)準(zhǔn)名稱(chēng)作為參數(shù)的類(lèi)。我們需要在遵循委派模型加載類(lèi)的自定義類(lèi)加載器實(shí)現(xiàn)中重寫(xiě)此方法。

另外,如果父類(lèi)加載器找不到請(qǐng)求的類(lèi),則loadClass()會(huì)調(diào)用此方法。如果沒(méi)有任何類(lèi)加載器的父類(lèi)找到該類(lèi),則默認(rèn)實(shí)現(xiàn)會(huì)拋出ClassNotFoundException異常。

getParent方法

 
 
 
 
  1. public final ClassLoader getParent()

此方法返回父類(lèi)加載器以進(jìn)行委派。某些實(shí)現(xiàn)使用null來(lái)表示啟動(dòng)類(lèi)加載器。

getResource方法

 
 
 
 
  1. public URL getResource(String name)

此方法嘗試查找具有給定名稱(chēng)的資源。它將首先委托給資源的父類(lèi)加載器,如果父級(jí)為null,則搜索虛擬機(jī)內(nèi)置的類(lèi)加載器的路徑。如果失敗,則該方法將調(diào)用findResource(String)來(lái)查找資源。

指定為輸入的資源名稱(chēng)可以相對(duì)于類(lèi)路徑,也可以是相對(duì)于絕對(duì)路徑。

它返回用于讀取資源的URL對(duì)象;如果找不到資源或調(diào)用者沒(méi)有足夠的特權(quán)來(lái)返回資源,則返回null。

需要注意的是,Java是從類(lèi)路徑中加載資源。

最后,Java中的資源加載被認(rèn)為是與位置無(wú)關(guān)的,因?yàn)橹灰O(shè)置了環(huán)境來(lái)查找資源,代碼在何處運(yùn)行都無(wú)關(guān)緊要。

上下文類(lèi)加載器

通常,上下文類(lèi)加載器為J2SE中引入的類(lèi)加載委托方案提供了一種替代方法。JVM中的類(lèi)加載器遵循分層模型,因此每個(gè)類(lèi)加載器都有一個(gè)單獨(dú)的父類(lèi),而啟動(dòng)類(lèi)加載器除外。但是,有時(shí)當(dāng)JVM核心類(lèi)需要?jiǎng)討B(tài)加載應(yīng)用程序開(kāi)發(fā)人員提供的類(lèi)或資源時(shí),可能會(huì)遇到問(wèn)題。

例如,在JNDI中,核心功能由rt.jar中的引導(dǎo)程序類(lèi)實(shí)現(xiàn)。但是這些JNDI類(lèi)可能會(huì)加載由獨(dú)立供應(yīng)商實(shí)現(xiàn)的JNDI提供程序(部署在應(yīng)用程序類(lèi)路徑中)。這種情況要求啟動(dòng)類(lèi)加載器(父類(lèi)加載器)加載對(duì)應(yīng)程序加載器(子類(lèi)加載器)可見(jiàn)的類(lèi)。

線程上下文類(lèi)加載器(context class loader)是從JDK 1.2開(kāi)始引入的。Java.lang.Thread中的方法 getContextClassLoader()和setContextClassLoader(ClassLoader cl)用來(lái)獲取和設(shè)置線程的上下文類(lèi)加載器。如果沒(méi)有通過(guò)setContextClassLoader(ClassLoader cl)方法進(jìn)行設(shè)置的話(huà),線程將繼承其父線程的上下文類(lèi)加載器。Java應(yīng)用運(yùn)行的初始線程的上下文類(lèi)加載器是系統(tǒng)類(lèi)加載器,在線程中運(yùn)行的代碼可以通過(guò)此類(lèi)加載器來(lái)加載類(lèi)和資源。

線程上下文類(lèi)加載器從根本解決了一般應(yīng)用不能違背雙親委派模式的問(wèn)題,使得java類(lèi)加載體系顯得更靈活。上面所提到的問(wèn)題正是線程上下文類(lèi)加載器的拿手好菜。如果不做任何的設(shè)置,Java應(yīng)用的線程上下文類(lèi)加載器默認(rèn)就是系統(tǒng)類(lèi)加載器。因此,在SPI接口的代碼中使用線程上下文類(lèi)加載器,就可以成功的加載到SPI實(shí)現(xiàn)的類(lèi)。

小結(jié)

類(lèi)加載器對(duì)于執(zhí)行Java程序是必不可少的。我們先學(xué)習(xí)了不同類(lèi)型的類(lèi)加載器,即Bootstrap類(lèi)加載器、擴(kuò)展類(lèi)加載器和系統(tǒng)類(lèi)加載器。Bootstrap類(lèi)加載器充當(dāng)所有類(lèi)加載器的父級(jí),負(fù)責(zé)加載JDK內(nèi)部類(lèi)。擴(kuò)展類(lèi)加載器和系統(tǒng)類(lèi)加載器分別從Java擴(kuò)展目錄和類(lèi)路徑加載類(lèi)。然后,我們學(xué)習(xí)了類(lèi)加載器的工作原理、特性,以及如何創(chuàng)建自定義類(lèi)加載器。


本文名稱(chēng):這一篇文章,可以把Java中的類(lèi)加載器了解的七七八八了
本文來(lái)源:http://www.dlmjj.cn/article/dpecise.html