一文入門類加載器

java.lang.class類

Class類的實例表示正在運行的Java應用程序中的類或接口. Class類沒有公共構造函數,那他是如何建立的呢? 咱們來看看官方文檔是如何說的java

Instead {@code Class} objects are constructed automatically by the Java Virtual Machine as classes are loaded and by calls to the {@code defineClass} method in the class loader.c++

Class對象是由Java虛擬機在加載類時自動構造的,並經過調用類加載器中的defineClass方法來構造. 每一個Class對象包含一個定義他的類加載器的引用.jvm

private final ClassLoader classLoader;函數

下面咱們就來認識一下類加載器.this


什麼是類加載器

看看jdk文檔怎麼說:spa

A class loader is an object that is responsible for loading classes.Given the binary name of a class, a class loader should attempt to locate or generate data that constitutes a definition for the classdebug

類加載器是負責加載類的對象,給定一個類的全限定名,類加載應該嘗試生成包含在類定義裏面的數據流 通俗點解釋就是: .java文件編譯後生成.class文件, 類加載器就是將.class文件轉換成java.lang.Class類的一個實例3d


類加載器的分類

啓動類加載器(BootstrapClassLoader)

負責加載系統類,由c語言實現,沒有對應的類加載器 加載路徑: System.getProperty("sun.boot.class.path");code

擴展類加載器(Extension Class Loader)

負責加載擴展類 加載路徑 System.getProperty("java.ext.dirs");cdn

應用類加載器(AppClassLoader)

從用戶類路徑下加載 加載路徑 System.getProperty("java.class.path");

驗證

System.out.println(String.class.getClassLoader()); // 加載系統類用到的類加載器
System.out.println(Student.class.getClassLoader()); // Student是用戶自定義的類
複製代碼

輸出一下查看結果

null
sun.misc.Launcher$AppClassLoader@18b4aac2
複製代碼

由於String是系統類,因此由BootstrapClassLoader加載,而BootstrapClassLoader沒有對應的類加載器,因此爲null

Student是在用戶類路徑下定義的,因此是由AppClassLoader加載


雙親委派機制

除了啓動類加載器外,全部的類加載器都有一個父類加載器。類加載器要先把加載類的機會交給他的父類加載器在父類加載器加載失敗時,他纔會加載該類

類加載器層次結構圖:

類加載2.png

加載Studeng類的過程: AppClassLoader先交給其父類ExtentsionClassLoader加載,ExtensionClassLoader交給他的父類BootstrapClassLoader加載,BootstrapClassLoader沒有父類加載器,嘗試加載,加載失敗,讓其子類ExtensionClassLoader加載,一樣加載失敗,交給其子類AppClassLoader加載,加載成功!

源碼追蹤

sun.misc.Launcher類

Launcher類是java應用的入口,由JVM建立的,源碼對外隱藏,只能經過反編譯查看. 爲何Launcher類是java應用的入口? 由於 ApplicationClassLoader和ExtClassLoader都是在Launcher類定義的

雙親委派機制源碼

ClassLoader類的loadClass()方法

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        // 加鎖機制
        synchronized (getClassLoadingLock(name)) {
            // 給定一個類的全限定名,檢查類是否被加載過,底層調用的c++方法,不須要深刻研究
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    // 先讓其父類加載
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        // 父類爲空,則讓BootStrapClassLoader加載該類
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    
                }

                if (c == null) {
                   
                    long t1 = System.nanoTime();
                     // 經過類的全限定名查找該類
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }
複製代碼

你們本身都debug幾遍,就能搞懂雙親委派機制的流程,我就不貼圖了,求關注


關注公衆號,免費領取優秀jvm入門書籍

相關文章
相關標籤/搜索