加載 → 驗證 → 準備 → 解析 → 初始化 → 使用 → 卸載 ↑ ↑ └────────────── 類加載過程 ────────────────────────┘
| 階段 | 核心任務 | 關鍵特點 |
|---|---|---|
| 加載 | 1. 獲取二進制位元組流 2. 轉換為方法區資料結構 3. 建立 java.lang.Class 物件 | 開發者可自定義類加載器控制來源 |
| 驗證 | 檢查 Class 檔案格式、語義、位元組碼合法性 | 確保 JVM 安全,防止惡意位元組碼 |
| 準備 | 為 static 變數分配記憶體、設定預設值 (零值) | 不執行 Java 程式碼,僅靜態分配 |
| 解析 | 符號參考 → 直接參考 (常量池、方法、欄位) | 可延遲到初始化後 (動態繫結) |
| 初始化 | 執行 | 類建構器,線程安全,父類優先初始化 |
Bootstrap ClassLoader (C/C++ 實現)
↑ 加載 JAVA_HOME/lib/*.jar
Extension ClassLoader
↑ 加載 JAVA_HOME/lib/ext/*.jar
Application ClassLoader (系統類加載器)
↑ 加載 classpath 下類別
Custom ClassLoader (使用者自定義)
protected Class> loadClass(String name, boolean resolve) throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
// 1. 檢查已加載
Class> c = findLoadedClass(name);
if (c == null) {
try {
// 2. 委派父加載器
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// 3. 父加載失敗,自身嘗試
c = findClass(name);
}
}
if (resolve) resolveClass(c);
return c;
}
}
只有以下 5 種情況會主動引用觸發初始化:
new、反射、反序列化建立實例// 1. 子類引用父類 static 欄位 → 僅初始化父類 System.out.println(SubClass.FROM_PARENT); // 只輸出 "Parent init" // 2. 陣列定義 Parent[] arr = new Parent[10]; // 不初始化 Parent // 3. 編譯期常數 (final + 基本型別/String) System.out.println(Constants.VERSION); // 直接從常量池讀取,不初始化類
| 特性 | ||
|---|---|---|
| 執行時機 | 類首次主動引用 | 每次 new 實例 |
| 執行內容 | static 變數賦值、static 區塊 | 非 static 變數賦值、構造區塊、建構子 |
| 父類關係 | JVM 保證父類 | 隱式/顯式 super() 呼叫父 |
| 線程安全 | JVM 加鎖同步 | 無特殊保證 |
| 可選性 | 無 static 成員則不生成 | 必須存在 (隱式預設建構子) |
# JVM 參數
-XX:+TraceClassLoading # 載入日誌
-XX:+TraceClassUnloading # 卸載日誌
-verbose:class # 簡易模式
# 程式碼註冊監聽 (Java 8+)
ClassLoader.getSystemClassLoader().registerAsParallelCapable();
Instrumentation inst = ...;
inst.addTransformer(new ClassFileTransformer() {
@Override
public byte[] transform(ClassLoader loader, String className, ...) {
System.out.println("Loading: " + className);
return null;
}
});
| 問題 | 原因分析 | 解決方案 |
|---|---|---|
| NoClassDefFoundError | 執行時找不到類 (編譯時存在) | 檢查 classpath、依賴衝突、類加載器隔離 |
| ClassNotFoundException | 反射/動態載入失敗 | 確認類名正確、驅動包存在 |
| LinkageError | 同一類被不同加載器載入 | 雙親委派破壞、模組化邊界問題 |
| StackOverflowError in | 靜態初始化循環依賴 | 重構靜態依賴、延遲初始化 |
| 記憶體洩漏 (Metaspace) | 動態生成大量類未卸載 | -XX:MaxMetaspaceSize、檢查類加載器引用 |