JVM學習之Java類加載

版權聲明:本文爲博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/qq_34560242/article/details/81002744

Java類加載

我們知道,java源代碼(*.java)不能直接執行,我們需要通過java編譯器javac.exe將源代碼編譯爲java字解碼文件(*.class),然後再通過java.exe在JVM中解釋此程序。

一、Java程序執行流程
這裏寫圖片描述
二、類加載器(ClassLoader)
這裏寫圖片描述
類加載器有以下幾種類型:

  • 1、啓動類加載器(Bootstrap ClassLoader):該ClassLoader是jvm在啓動時創建的,用於加載 $JAVA_HOME/jre/lib下面的類庫(或者通過參數-Xbootclasspath指定)。由於引導類加載器涉及到虛擬機本地實現細節,開發者無法直接獲取到啓動類加載器的引用,所以不能直接通過引用進行操作。

  • 2、擴展類加載器(ExtClassLoader):該ClassLoader是在sun.misc.Launcher裏作爲一個內部類ExtClassLoader定義的(即 sun.misc.Launcher.ExtClassLoader),ExtClassLoader會加載 $JAVA_HOME/jre/lib/ext下的類庫(或者通過參數-Djava.ext.dirs指定)。

  • 3、 應用程序類加載器(AppClassLoader):應用程序類加載器,該ClassLoader同樣是在sun.misc.Launcher裏作爲一個內部類AppClassLoader定義的(即 sun.misc.Launcher.AppClassLoader),AppClassLoader會加載java環境變量CLASSPATH所指定的路徑下的類庫,而CLASSPATH所指定的路徑可以通過System.getProperty(“java.class.path”)獲取;當然,該變量也可以覆蓋,可以使用參數-cp,例如:java -cp 路徑 (可以指定要執行的class目錄)。

  • 4、自定義類加載器(CustomClassLoader):該ClassLoader是指我們自定義的ClassLoader,比如tomcat的StandardClassLoader屬於這一類;當然,大部分情況下使用AppClassLoader就足夠了。

三、雙親委派加載機制

  • 1、類加載源碼:
protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    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;
        }
    }
  • 2、加載過程:
    • 1)、首先驗證這個類是否已經加載過,如果加載過直接返回。
    • 2)、如果沒有加載過,再去判斷是否有父加載器。如果有就遞歸調用父加載器驗證是否加載此類。
    • 3)、如果沒有父類加載器則調用啓動類加載器(Bootstrap ClassLoader)加載此類。
    • 4)、如果啓動類加載器(Bootstrap ClassLoader)也未找到此類,則會調用findClass(name)進行加載。
    • 5)、如果findClass(name)還未找到就拋ClassNotFoundException異常。

四、雙親委派加載機制好處

  • 1、避免類被重複加載
  • 2、安全:假如自定義一個Java中已經有的類,初始化的時候JVM會先委託BootStrapClassLoader加載JDK中已有的類,而自定義的類永遠都不會被加載。

五、類加載詳細過程
這裏寫圖片描述

  • 1、加載:類加載階段就是由類加載器負責根據一個類的全限定名來讀取此類的二進制字節流到JVM內部,並存儲在運行時內存區的方法區,然後將其轉換爲一個與目標類型對應的java.lang.Class對象實例(Java虛擬機規範並沒有明確要求一定要存儲在堆區中,只是hotspot選擇將Class對象存儲在方法區中),這個Class對象在日後就會作爲方法區中該類的各種數據的訪問入口。
  • 2、連接:是將加載到JVM中的二進制字節流的類數據信息合併到JVM的運行時狀態中,經由驗證、準備、解析三個階段。
    • 驗證:驗證類數據信息是否符合JVM規範,是否是一個有效的字節碼文件,驗證內容涵蓋了類數據信息的格式驗證、語義分析、操作驗證等
    • 準備:爲類中的所有靜態變量分配內存空間,併爲其設置一個初始值(由於還沒有產生對象,實例變量將不再此操作範圍內)。
    • 解析:將常量池中所有的符號引用轉爲直接引用(得到類或者字段、方法在內存中的指針或者偏移量,以便直接調用該方法)。這個階段可以在初始化之後再執行。
  • 3、初始化:對類內存數據進行初始化賦值等。
  • 4、使用:…
  • 5、卸載:類使用完成之後,根據其情況進行GC操作。

六、類初始化順序

Foo.java

public class Foo {

    public Foo() {
        System.out.println("Foo.constructor...");
    }

    static {
        System.out.println("Foo.static...");
    }

    {
        System.out.println("Foo...");
    }
}

Son.java

public class Son extends Foo {

    public Son() {
        System.out.println("Son.constructor...");
    }

    static {
        System.out.println("Son.static...");
    }

    {
        System.out.println("Son...");
    }

    public static void main(String[] args) {
        new Son();
    }
}

控制檯

Foo.static...
Son.static...
Foo...
Foo.constructor...
Son...
Son.constructor...

初始化說明:

  • 1、父類靜態資源
  • 2、子類靜態資源
  • 3、父類非靜態資源
  • 4、父類構造函數
  • 5、子類非靜態資源
  • 6、子類構造函數
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章