<clinit>) 與靜態字段賦值除解析外,步驟順序嚴格固定。
| 方法 | 簽名 | 核心功能 |
|---|---|---|
| 入口方法 | loadClass(String name, boolean resolve) | 協調加載流程:檢查緩存 → 委派父加載器 → 自定義加載 → 可選解析 → 返回 Class |
| 定義類 | defineClass(byte[] b, int off, int len) | 將字節數組解析為 Class 對象 (驗證、準備、解析) |
| 系統加載 | findSystemClass(String name) | 從本地文件系統加載 (默認機制,調用 defineClass) |
| 解析類 | resolveClass(Class c) | 觸發解析階段 (符號引用→直接引用) |
| 查找已加載 | findLoadedClass(String name) | 檢查緩存,避免重複加載 (重複會拋 LinkageError) |
public abstract class MultiClassLoader extends ClassLoader {
private Map cache = new HashMap<>();
public synchronized Class loadClass(String name, boolean resolve)
throws ClassNotFoundException {
// 1. 檢查緩存
Class cached = cache.get(name);
if (cached != null) return cached;
// 2. 委派系統加載器 (父加載器)
try {
Class systemClass = super.findSystemClass(name);
return systemClass;
} catch (ClassNotFoundException e) {
// 非系統類,繼續自定義加載
}
// 3. 獲取字節碼 (抽象方法,子類實現具體來源:文件/網絡/數據庫/加密解密等)
byte[] classBytes = loadClassBytes(name);
if (classBytes == null) throw new ClassNotFoundException();
// 4. 定義類
Class clazz = defineClass(null, classBytes, 0, classBytes.length);
if (clazz == null) throw new ClassFormatError();
// 5. 可選解析
if (resolve) resolveClass(clazz);
// 6. 緩存並返回
cache.put(name, clazz);
return clazz;
}
protected abstract byte[] loadClassBytes(String name);
}
Bootstrap ClassLoader (C++ 實現, 加載 rt.jar 核心庫)
↑
Extension ClassLoader (加載 jre/lib/ext/*.jar)
↑
System/Application ClassLoader (加載 CLASSPATH, 默認父加載器)
↑
Custom ClassLoaders (Applet/網絡/熱部署/加密/隔離等場景)
核心規則:子加載器先委派父加載器,父加載器無法加載時子加載器才嘗試。
| 加載器 | 父加載器 | 實現語言 | 加載來源 | 典型用途 |
|---|---|---|---|---|
| Bootstrap | 無 | Native (C++) | sun.boot.class.path (rt.jar 等) | Java 核心庫,受信任,跳過安全檢查 |
| Extension | Bootstrap | Java | java.ext.dirs (擴展目錄) | 標準擴展 API |
| System/Application | Extension | Java | java.class.path (CLASSPATH) | 應用主類、第三方庫,用戶自定義加載器默認父加載器 |
| Applet | System | Java | 網絡 CodeBase | 瀏覽器 Applet 隔離加載 |
結果:用戶類由自定義加載器加載,核心庫由父加載器加載,實現隔離與共享平衡。
Class.getClassLoader() 獲取定義加載器類加載是 JVM 動態性的基石。雙親委派模型保證了核心庫安全與共享,自定義 ClassLoader 賦予了應用級的加載控制權。深入理解 loadClass 委派邏輯、defineClass 定義過程、緩存機制與類身份判定,是掌握 Java 動態特性、排查 ClassNotFound/Linkage/ClassCast 異常、構建模塊化系統的關鍵。