首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java 類加載器深度解析:雙親委派模型、自定義 ClassLoader 與類卸載機制

     編輯:Java 綜合教學

三大核心類加載器

加載器稱呼職責範圍
Bootstrap ClassLoader啟動類加載器加載 JDK 核心庫(rt.jar、resources.jar、charsets.jar 等)
Extension ClassLoader擴展類加載器加載 JAVA_HOME/jre/lib/ext/ 目錄下所有 JAR
App ClassLoader系統類加載器加載應用程式 classpath 下所有類與 JAR

查看 Bootstrap 加載路徑

// 方式一
URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
for (URL url : urls) System.out.println(url.toExternalForm());

// 方式二
System.out.println(System.getProperty("sun.boot.class.path"));

雙親委派模型原理

工作流程

  1. 子加載器收到加載請求,先委派給父加載器
  2. 父加載器繼續向上委派,直到 Bootstrap ClassLoader
  3. 若父加載器無法加載,子加載器才嘗試自行加載
  4. 全鏈路都失敗則拋出 ClassNotFoundException

設計優勢

  • 避免重複加載:父已加載則子不再重複工作
  • 安全性保障:核心類(如 java.lang.String)只能由 Bootstrap 加載,防止惡意代碼替換核心 API

類身份判定規則

JVM 判定兩個類是否相同,需同時滿足:

  • 類全限定名相同
  • 由同一個 ClassLoader 實例加載

即使字節碼完全一致,不同加載器加載也視為不同類。

自定義 ClassLoader 實戰

方案一:繼承 ClassLoader(需重寫 findClass)

public class NetworkClassLoader extends ClassLoader {
    private String rootUrl;
    public NetworkClassLoader(String rootUrl) { this.rootUrl = rootUrl; }
    
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] classData = getClassData(name);  // 從網絡/文件獲取字節碼
        if (classData == null) throw new ClassNotFoundException();
        return defineClass(name, classData, 0, classData.length);
    }
    // getClassData() 實現略...
}

方案二:繼承 URLClassLoader(更簡潔)

public class SimpleURLClassLoader extends URLClassLoader {
    public static String projectClassPath = "E:/workspace/project/bin/";
    
    public SimpleURLClassLoader() {
        super(getMyURLs());  // 指定掃描路徑
    }
    
    @Override
    protected Class<?> loadClass(String name, boolean resolve) 
            throws ClassNotFoundException {
        // 可選:打破雙親委派,實現熱插拔
        // 但 java.* 開頭類仍由系統加載器處理
    }
}

類卸載條件(GC 回收)

類必須同時滿足三條件才能被卸載:

  1. 該類所有實例已被 GC
  2. 加載該類的 ClassLoader 實例已被 GC
  3. 該類 java.lang.Class 對象無任何引用

注意:GC 時機不可控,類卸載同樣不可控。

驗證類卸載示例

SimpleURLClassLoader loader = new SimpleURLClassLoader();
Class clazzA = loader.load("testjvm.testclassloader.A");
Object a = clazzA.newInstance();

// 清除所有引用
a = null;
clazzA = null;
loader = null;

System.gc();  // 僅建議執行 GC
System.out.println("GC over");

參考文檔:
CSDN 類加載詳解 | OSChina 類加載實戰

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved