.class 字節碼(文件、網絡、動態生成)。java.lang.Class 對象(方法區存儲元數據,堆創建 Class 實例)。java.lang.String)。
Bootstrap ClassLoader (C++ 實現,無 Java 對象)
↑ 父
Extension ClassLoader (sun.misc.Launcher$ExtClassLoader)
↑ 父
System/Application ClassLoader (sun.misc.Launcher$AppClassLoader) ← 類路徑
↑ 父
Custom ClassLoader (用戶自定義)
ClassNotFoundException),子加載器調用 findClass() 自行加載。優勢:避免重複加載、保護核心類不被篡改(如用戶自定義 java.lang.String 永不會被加載,因 Bootstrap 優先找到系統類)。
ClassLoader cl = ClassLoader.getSystemClassLoader();
while (cl != null) {
System.out.println(cl);
System.out.println("parent: " + cl.getParent());
cl = cl.getParent();
}
// 輸出:
// sun.misc.Launcher$AppClassLoader@19821f
// parent: sun.misc.Launcher$ExtClassLoader@addbf1
// sun.misc.Launcher$ExtClassLoader@addbf1
// parent: null ← 代表 Bootstrap
ClassLoader。findClass(String name):獲取字節碼 → defineClass() 轉換為 Class 對象。
public class MyClassLoader extends ClassLoader {
private String basePath; // 字節碼來源路徑/URL
public MyClassLoader(String basePath) { this.basePath = basePath; }
@Override
protected Class> findClass(String name) throws ClassNotFoundException {
byte[] classData = loadClassData(name); // 從文件/網絡/DB 讀取 byte[]
if (classData == null) throw new ClassNotFoundException(name);
return defineClass(name, classData, 0, classData.length);
}
private byte[] loadClassData(String name) {
// 實現:讀取 {basePath}/{name}.class 文件或 HTTP 請求
// 返回 byte[] 或 null
}
}
getResourceAsStream(name) / getResource(name):獲取資源流/URL。defineClass(name, byte[], off, len, ProtectionDomain):字節碼 → Class 對象(final,不可覆寫)。resolveClass(Class):鏈接階段(驗證、準備、解析),loadClass(..., true) 會自動調用。
URL[] urls = {new URL("file:/c:/")};
URLClassLoader ucl1 = new URLClassLoader(urls);
URLClassLoader ucl2 = new URLClassLoader(urls);
Class> c1 = ucl1.loadClass("Foo");
Class> c2 = ucl2.loadClass("Foo");
System.out.println(c1 == c2); // false
c1.newInstance(); // counter: 1
c2.newInstance(); // counter: 1 (各自獨立靜態初始化)
這是熱部署、模塊化隔離(OSGi、Spring Boot DevTools、Tomcat 熱加載)的理論基礎。
WEB-INF/classes、WEB-INF/lib。**優先自行加載(打破雙親委派)**,實現應用間類隔離、版本衝突解耦。| 方式 | 觸發時機 | 是否初始化 |
|---|---|---|
隱式 new Xxx() | 首次主動使用類 | 是(執行 <clinit>) |
顯式 Class.forName("Xxx") | 調用時 | 默認是(forName0(name, true, callerCL)) |
顯式 Class.forName("Xxx", false, loader) | 調用時 | 否(僅加載鏈接,不執行靜態初始化) |
顯式 loader.loadClass("Xxx") | 調用時 | 否(同 forName(..., false)) |