05. 類加載器

類加載器

類加載器用來把類加載到Java虛擬機(jī)中,從JDK1.2版本開始,類的加載過程采用雙親委派機(jī)制,這種雙親委派機(jī)制能更好地保證Java平臺(tái)的安全,在此機(jī)制中,除了Java虛擬機(jī)自帶的根類加載器之外,其余的類加載器都有且只有一個(gè)父類加載器,當(dāng)Java程序請(qǐng)求加載器loader1加載Sample類時(shí),loader1首先委托自己的父加載器去加載Sample類,若父加載器能加載,則有父加載器完成加載任務(wù),否則才由加載器loader1本身加載Sample類

Java虛擬機(jī)自帶了以下幾種類加載器

  • 根(啟動(dòng))類加載器(Bootstrap),該加載器沒有父加載器,它負(fù)責(zé)加載虛擬機(jī)的核心類庫(kù),如java.lang.*等,根類加載器的實(shí)現(xiàn)依賴于底層操作系統(tǒng),屬于虛擬機(jī)的實(shí)現(xiàn)的一部分,它沒有繼承java.lang.ClassLoader類
  • 擴(kuò)展類加載器(Extension),它的父類加載器為根(啟動(dòng))類加載器,它從java.ext.dirs系統(tǒng)屬性所指定的目錄中加載類庫(kù),或者從JDK的安裝目錄的jre\lib\ext子目錄(擴(kuò)展目錄)下加載類庫(kù),如果把用戶創(chuàng)建的JAR文件放在這個(gè)目錄下,也會(huì)自動(dòng)由擴(kuò)展類加載器加載。擴(kuò)展類加載器是純Java類,是java.lang.ClassLoader類的子類
  • 系統(tǒng)(應(yīng)用)類加載器(System),也稱應(yīng)用類加載器,它的父類加載器是擴(kuò)展類加載器,它從環(huán)境變量classpath或者系統(tǒng)屬性java.class.path所指定的目錄中加載類,它是用戶自定義的類加載器的默認(rèn)父加載器。系統(tǒng)類加載器是純Java類,是java.lang.ClassLoader類的子類

除了以上虛擬機(jī)自帶的加載器外,用戶還可以定制自己的類加載器。Java提供了抽象類java.lang.ClassLoader,所有用戶自定義的類加載器都應(yīng)該繼承ClassLoader類。


002. 類層次關(guān)系圖.png

我們通過代碼再次理解上述層次關(guān)系圖

public class MyTest13 {
    public static void main(String[] args) {
        // 獲取系統(tǒng)類加載器
        ClassLoader classLoader = ClassLoader.getSystemClassLoader();
        System.out.println(classLoader);
        while (null != classLoader) {
            // 獲取該類加載器的父加載器
            classLoader = classLoader.getParent();
            System.out.println(classLoader);
        }
    }
}

有些實(shí)現(xiàn)可能使用null表示啟動(dòng)類加載器,在這種實(shí)現(xiàn)中,如果是啟動(dòng)類加載器加載的將返回null

從圖上可以看出,類加載器好像是層次結(jié)構(gòu),但真實(shí)情況是包含關(guān)系,子加載器包含父加載器的引用

數(shù)組對(duì)應(yīng)的類不是由類加載器加載的,他們是在程序運(yùn)行時(shí)自動(dòng)創(chuàng)建出來的,通過Class.getClassLoader()方法可以獲取類對(duì)應(yīng)的加載器,對(duì)于數(shù)組來說,返回的是數(shù)組元素對(duì)應(yīng)的類加載器信息,如果是原生類型,沒有類加載器,可以通過下述代碼驗(yàn)證該結(jié)論

public class MyTest15 {
    public static void main(String[] args) {
        String[] strings = new String[2];
        // 啟動(dòng)類加載器
        System.out.println(strings.getClass().getClassLoader());

        // 系統(tǒng)類加載器
        MyTest15[] myTest15s = new MyTest15[2];
        System.out.println(myTest15s.getClass().getClassLoader());

        int[] nums = new int[2];
        // 原生類型沒有class loader 為 null
        System.out.println(nums.getClass().getClassLoader());

    }
}

獲取ClassLoader的途徑

  1. 獲取當(dāng)前類的ClassLoader

    clazz = Class.forName("com.zj.study.jvm.classloader.CL");
    ClassLoader classLoader = clazz.getClassLoader();
    
  2. 獲取當(dāng)前線程上下文的ClassLoader

    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    System.out.println(classLoader);
    
  3. 獲取系統(tǒng)的ClassLoader

    ClassLoader classLoader = ClassLoader.getSystemClassLoader();
    System.out.println(classLoader);
    
  4. 獲取調(diào)用者的ClassLoader

    DriverManager.getCallerClassLoader()
    

前三種用的比較多

啟動(dòng)類加載器

在運(yùn)行期,一個(gè)Java類是由該類的完全限定名(binary name,二進(jìn)制名)和用于加載該類的定義類加載器(defining class)所共同決定的。
如果同樣名字(即相同的完全限定名)的類是由兩個(gè)不同的加載器所加載,那么這些類是不同的,即便.class文件的字節(jié)碼完全一樣,并且從相同的位置加載

擴(kuò)展類加載器和系統(tǒng)類加載器本身也是java類,他們由誰加載?
內(nèi)建于JVM中的啟動(dòng)類加載器會(huì)加載java.lang.ClassLoader(擴(kuò)展類加載器和系統(tǒng)類加載器在其中)以及其他的Java平臺(tái)類,當(dāng)JVM啟動(dòng)時(shí),一塊特殊的機(jī)器碼會(huì)運(yùn)行,它會(huì)加載擴(kuò)展類加載器與系統(tǒng)類加載器,這塊特殊的機(jī)器碼叫做啟動(dòng)類加載器(Bootstrap)

啟動(dòng)類加載器并不是Java類,而其他的加載器則都是Java類
啟動(dòng)類加載器是特定于平臺(tái)的機(jī)器指令,它負(fù)責(zé)開啟整個(gè)加載過程

所有類加載器(除了啟動(dòng)類加載器)都被實(shí)現(xiàn)為Java類,不過,總歸要有一個(gè)組件來加載第一個(gè)Java類加載器,從而讓整個(gè)加載都能夠順利進(jìn)行下去,加載第一個(gè)純Java類加載器就是啟動(dòng)類加載器的職責(zé)
啟動(dòng)類加載器還會(huì)負(fù)責(zé)負(fù)責(zé)加載提供JRE正常運(yùn)行所需要的基本組件,這包括java.util與java.lang包中的類等等
驗(yàn)證

public class MyTest22 {
    public static void main(String[] args) {
        System.out.println(System.getProperty("sun.boot.class.path"));
        System.out.println(System.getProperty("java.ext.dirs"));
        System.out.println(System.getProperty("java.class.path"));
        System.out.println("---------");
        System.out.println(ClassLoader.class.getClassLoader());
        System.out.println("---------");
        // 怎么驗(yàn)證系統(tǒng)類加載器和擴(kuò)展類加載器是由啟動(dòng)類加載器加載的?
        // 啟動(dòng)類加載器和擴(kuò)展類加載器是Launcher的內(nèi)部類,所以加載Launcher的類加載器會(huì)嘗試加載系統(tǒng)類加載器和擴(kuò)展類加載器,
        // 所以只需要驗(yàn)證Launcher類是由誰加載的即可
        System.out.println(Launcher.class.getClassLoader());
    }
}

系統(tǒng)類加載器

If the system property "java.system.class.loader" is defined when this method is first invoked then the value of that property is taken to be the name of a class that will be returned as the system class loader. The class is loaded using the default system class loader and must define a public constructor that takes a single parameter of type ClassLoader which is used as the delegation parent. An instance is then created using this constructor with the default system class loader as the parameter. The resulting class loader is defined to be the system class loader.
大概意思就是說系統(tǒng)類加載器可以指定
驗(yàn)證
java -Djava.system.class.loader=com.zj.study.jvm.classloader.MyAppClassLoader com.zj.study.jvm.classloader.MyTest22
使用如下命令啟動(dòng)

public class MyTest22 {
    public static void main(String[] args) {
        // 自定義的類加載器成為系統(tǒng)類加載器
        // java -Djava.system.class.loader=com.zj.study.jvm.classloader.MyAppClassLoader com.zj.study.jvm.classloader.MyTest22
        System.out.println("---------");
        System.out.println(System.getProperty("java.system.class.loader"));
        System.out.println(MyTest22.class.getClassLoader());
        System.out.println(MyAppClassLoader.class.getClassLoader());
        System.out.println(ClassLoader.getSystemClassLoader());
    }
}
最后編輯于
?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 類加載器是 Java 語言的一個(gè)創(chuàng)新,也是 Java 語言流行的重要原因之一。它使得 Java 類可以被動(dòng)態(tài)加載到...
    CHSmile閱讀 1,673評(píng)論 0 12
  • 虛擬機(jī)把描述類的數(shù)據(jù)從Class文件加載到內(nèi)存, 并對(duì)數(shù)據(jù)進(jìn)行校驗(yàn)、轉(zhuǎn)換解析和初始化, 最終形成可以被虛擬機(jī)直接使...
    好好學(xué)習(xí)Sun閱讀 1,382評(píng)論 0 3
  • 代碼編譯的結(jié)果從本地機(jī)器碼轉(zhuǎn)變?yōu)樽止?jié)碼,是存儲(chǔ)格式發(fā)展的一小步,確實(shí)編譯語言發(fā)展的一大步。 虛擬機(jī)把描述類的數(shù)據(jù)從...
    胡二囧閱讀 1,070評(píng)論 0 0
  • JVM類加載器ClassLoader JAVA類裝載方式 1.隱式裝載, 程序在運(yùn)行過程中當(dāng)碰到通過new 等方式...
    步二小哥閱讀 474評(píng)論 0 1
  • 一:ClassLoader 從JVM結(jié)構(gòu)圖中可以看到,類加載器的作用是將Java類文件加載到Java虛擬機(jī)。 只有...
    阿菜的博客閱讀 1,888評(píng)論 0 8

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