Java 類(lèi)加載器

一、概述

上篇文章中概述了類(lèi)的加載流程,那么類(lèi)是由什么來(lái)加載的呢?毫無(wú)疑問(wèn)就是類(lèi)加載器,類(lèi)加載器是Java中很重要的概念,它負(fù)責(zé)將字節(jié)碼文件加載到Jvm虛擬機(jī)中。在Java中有三大類(lèi)加載器:?jiǎn)?dòng)類(lèi)加載器,擴(kuò)展類(lèi)加載器,應(yīng)用程序類(lèi)加載器。

二、啟動(dòng)類(lèi)加載器

啟動(dòng)類(lèi)加載器(Bootstrap ClassLoader)是由c/c++語(yǔ)言實(shí)現(xiàn)的,是JVM的一部分。
它用來(lái)加載Java的核心類(lèi)庫(kù):rt.jar,resources.jar或sun.boot.class.path下的內(nèi)容。

三、擴(kuò)展類(lèi)加載器

擴(kuò)展類(lèi)加載器(Extension ClassLoader)是由Java語(yǔ)言編寫(xiě),由sun.misc.Launcher$ExtClassLoader實(shí)現(xiàn)。
派生于ClassLoader類(lèi)。父類(lèi)加載器為啟動(dòng)類(lèi)加載器。
它用來(lái)加載Java_HOME/lib/ext中的類(lèi),以及 java.ext.dirs系統(tǒng)屬性所指定的目錄中的類(lèi)庫(kù)。

四、應(yīng)用程序類(lèi)加載器

應(yīng)用程序類(lèi)加載器(AppClassLoader)是由Java語(yǔ)言編寫(xiě),由sun.misc.Launcher$AppClassLoader實(shí)現(xiàn)。
派生于ClassLoader類(lèi),父類(lèi)加載器為擴(kuò)展類(lèi)加載器。
復(fù)雜加載環(huán)境變量中classpath或系統(tǒng)屬性java.class.path指定路徑下的類(lèi)庫(kù)。
應(yīng)用程序類(lèi)加載器是程序中默認(rèn)的類(lèi)加載器,一般Java應(yīng)用的類(lèi)都是由它完成加載。

public class Main {
    public static void main(String[] args) {
        ClassLoader loader = ClassLoader.getSystemClassLoader();
        System.out.println(loader);
        System.out.println(loader.getParent());
    }
}

輸出:
sun.misc.Launcher$AppClassLoader@73d16e93
sun.misc.Launcher$ExtClassLoader@15db9742


五、雙親委派機(jī)制

  1. 如果一個(gè)類(lèi)加載器收到了類(lèi)加載的請(qǐng)求,他并不會(huì)自己去加載,而是把這個(gè)請(qǐng)求委托給父類(lèi)加載器。
  2. 如果父類(lèi)加載器還存在父類(lèi)加載器,則進(jìn)一步向上委托,直到請(qǐng)求達(dá)到最頂層的啟動(dòng)類(lèi)加載器。
  3. 如果父類(lèi)加載器可以完成類(lèi)的加載則返回,如果父類(lèi)加載器無(wú)法完成加載任務(wù),子加載器才會(huì)嘗試自己去加載。這就是雙親委派機(jī)制。

舉個(gè)例子:
假如我在項(xiàng)目目錄下創(chuàng)建一個(gè)java.lang的包,然后再創(chuàng)建一個(gè)String類(lèi),代碼如下:

package java.lang;

public class String {
    static {
        System.out.println("我是自定義的String");
    }
}

然后我們來(lái)使用String:

class Test {
    public static void main(String[] args) {
        java.lang.String str = new java.lang.String();
        System.out.println("Hello");
    }
}

此時(shí)運(yùn)行,這個(gè)String到底是哪個(gè)String呢?自定義的String還是Java核心庫(kù)中的String呢?我們運(yùn)行看下輸出:

Hello

控制臺(tái)只輸出了Hello,而我們自定義的String中的靜態(tài)代碼塊并沒(méi)有執(zhí)行,說(shuō)明加載的是Java核心庫(kù)的String。
可以說(shuō)如果你自己創(chuàng)建了一個(gè)和Java庫(kù)中同名的類(lèi),那么你的類(lèi)永遠(yuǎn)得不到加載。

在這個(gè)例子中,如果Java使用Test的類(lèi)加載器即應(yīng)用程序加載器加載String,那么加載的就是我們自定義的String了,但是如果加載了自定義的String,萬(wàn)一你自定義的String有毒咋整?所以這就是為什么會(huì)有雙親委派機(jī)制。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容