類加載是 Java 程式執行的第一步,深入理解其機制不僅有助於排查 ClassNotFoundException、NoClassDefFoundError 等經典問題,更是實現熱部署、模組化架構的基石。本文將從類生命週期、加載器層級、雙親委派模型、自定義加載器等維度全景解析。

類從編譯為 .class 到 JVM 執行,經歷:載入 → 驗證 → 準備 → 解析 → 初始化 → 使用 → 卸載。其中「載入」是開發者可控制的關鍵環節。
Bootstrap ClassLoader (C++ 實現,載入 jre/lib/rt.jar)
↑ 父加載器
Extension ClassLoader (載入 jre/lib/ext/*.jar)
↑ 父加載器
Application ClassLoader (載入 classpath 下類)
↑ 父加載器
自定義 ClassLoader (開發者自行實現)
ClassNotFoundException),子加載器嘗試自行載入public class ClassLoaderDemo {
public static void main(String[] args) {
ClassLoader loader = ClassLoaderDemo.class.getClassLoader();
System.out.println(loader); // sun.misc.Launcher$AppClassLoader
System.out.println(loader.getParent()); // sun.misc.Launcher$ExtClassLoader
System.out.println(loader.getParent().getParent()); // null (Bootstrap 由 C++ 實現)
}
}
| 方式 | 語法 | 是否執行初始化(<clinit>) | 典型場景 |
|---|---|---|---|
| 命令行啟動 | JVM 隱式載入 Main 類 | 是 | 程式入口 |
| Class.forName() | Class.forName("com.xxx.Foo") | 預設是;forName(name, false, loader) 可跳過 | JDBC 驅動註冊、SPI 機制 |
| ClassLoader.loadClass() | loader.loadClass("com.xxx.Foo") | 否(僅載入到方法區) | 動態載入、熱插拔 |
public class MyClassLoader extends URLClassLoader {
public MyClassLoader(URL[] urls) {
super(urls);
}
@Override
protected Class> findClass(String name) throws ClassNotFoundException {
// 可在此處實現加密解密、網路下載、編譯生成等邏輯
return super.findClass(name);
}
}
// 使用示例
URL url = new URL("file:/D:/myapp/classes/");
ClassLoader myLoader = new MyClassLoader(new URL[]{url});
Class> clazz = myLoader.loadClass("com.example.Plugin");
Object instance = clazz.getDeclaredConstructor().newInstance();
java.lang.String 等核心類(Bootstrap 已優先載入)ClassA.class.getClassLoader() != ClassB.class.getClassLoader())類加載機制是 Java 動態性的基石。掌握雙親委派模型、三大系統加載器職責、forName 與 loadClass 的初始化差異、自定義加載器編寫模式,能讓您從容應對類衝突、熱更新、插件架構等高階課題。