一文讀懂類加載機制

類記載過程

多個java文件通過編譯打包生成可運行的jar包,最終由java命令運行某個主類的main函數啓動程序,這裏首先須要經過類加載器把主類加載到jvm。
主類在運行過程當中若是使用到其餘類,會逐步加載這些類。
注意,jar包裏的類不是一次性所有加載的,是使用時才加載的。java

從類加載到使用整個過程由以下幾步:
加載、驗證、準備、解析、初始化、使用、卸載web

  • 加載:在硬盤上查找並經過IO讀入字節碼文件,使用到類時纔會加載,例如:調用類的main方法,new對象等;
  • 驗證:校驗字節碼文件的正確性;
  • 準備:給類的靜態變量分配內存,並賦予默認值;
  • 解析:將符號引用替換爲直接引用,該階段會把一些靜態方法(符號引用,好比main方法)替換爲指向數據所在內存的指針或句柄等(直接引用),這就是靜態連接過程,這個過程是在類記載期間完成的。動態連接是程序運行期間完成的將符號引用替換爲直接引用。
  • 初始化:對類的靜態變量初始化爲指定的值,執行靜態代碼塊。
    編程

    類加載器

    上面的類加載過程主要是經過類加載器來實現的,java裏有如下幾種類加載器。
  • 啓動類加載器:負責加載支撐JVM運行的位於JREd額lib目錄下的核心類庫;
  • 擴展類加載器:負責加載支撐JVM運行位於JRE的lib目錄下的ext擴展目錄中的JAR類包;
  • 應用程序加載器:負責加載ClassPath路徑下的類包,主要就是加載應用程序的類;
  • 自定義加載器:負責加載用戶自定義路徑下的類包;後端

類記載器繼承了java.lang.ClassLoader類,該類有兩個核心方法,loadClass和findClass。機器學習

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;
    }
}

findClass方法默認實現是拋出異常,因此咱們在自定義類加載器主要是重寫findClass方法。jvm

protected Class<?> findClass(String name) throws ClassNotFoundException {
    throw new ClassNotFoundException(name);
}

雙親委派機制

jvm類加載器是有親子層結構的.編程語言

這裏類加載就是雙親委派機制,記載某個類時, 會先委託父加載器尋找目標類,找不到再委託上層父加載器加載,若是全部父加載器再本身的加載類路徑下都找不到目標類,則再本身的類加載路徑中查找並載入目標類。函數

好比:Math類,最早會找應用程序類加載器加載,應用程序加載器會先委託擴展類加載器加載,擴展類加載器再委託啓動類加載器,頂層啓動類加載器在本身的類加載器路徑裏找了半天沒找到Math類,則向下退回加載Math類的請求,擴展類加載器收到回覆就本身加載,在本身的類加載路徑裏找了半天也沒找到Math類,又向下退回Math類的加載請求給應用程序類加載器,應用程序類加載器因而在本身的類加載路徑中找到了Math類,因而就本身加載了。工具

雙親委派機制說簡單就是:先找父親加載,不行再由父親本身加載。學習

還沒關注個人公衆號?

  • 掃文末二維碼關注公衆號【小強的進階之路】可領取以下:
  • 學習資料: 1T視頻教程:涵蓋Javaweb先後端教學視頻、機器學習/人工智能教學視頻、Linux系統教程視頻、雅思考試視頻教程;
  • 100多本書:包含C/C++、Java、Python三門編程語言的經典必看圖書、LeetCode題解大全;
  • 軟件工具:幾乎包括你在編程道路上的可能會用到的大部分軟件;
  • 項目源碼:20個JavaWeb項目源碼。
    小強的進階之路二維碼
相關文章
相關標籤/搜索