| 加載器 | 實現類 | 加載路徑 | 父加載器 |
|---|---|---|---|
| Bootstrap ClassLoader | C++ 實現 (JVM 內置) | %JAVA_HOME%/jre/lib, -Xbootclasspath | null (頂層) |
| Extension ClassLoader | sun.misc.Launcher$ExtClassLoader | %JAVA_HOME%/jre/lib/ext, java.ext.dirs | Bootstrap |
| Application ClassLoader | sun.misc.Launcher$AppClassLoader | classpath, -cp, Class-Path | Extension |
protected synchronized Class> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
// 1. 檢查緩存
Class> c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
// 2. 委派父加載器
c = parent.loadClass(name, false);
} else {
// 3. 無父加載器,委派 Bootstrap
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// 4. 父加載失敗,自身查找
c = findClass(name);
}
}
if (resolve) resolveClass(c);
return c;
}
Thread.currentThread().setContextClassLoader(appClassLoader),使用線程上下文類加載器反向委派WebappClassLoader,優先自加載,再委派父加載器 (打破標準委派)defineClasspublic class CustomClassLoader extends ClassLoader {
private final String basePath;
public CustomClassLoader(String basePath) {
this.basePath = basePath;
}
@Override
protected Class> findClass(String name) throws ClassNotFoundException {
byte[] classData = loadClassData(name);
if (classData == null) {
throw new ClassNotFoundException(name);
}
return defineClass(name, classData, 0, classData.length);
}
private byte[] loadClassData(String name) {
String path = basePath + name.replace('.', '/') + ".class";
try (InputStream is = new FileInputStream(path);
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
byte[] buffer = new byte[4096];
int len;
while ((len = is.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
return baos.toByteArray();
} catch (IOException e) {
return null;
}
}
}
// 使用
CustomClassLoader loader = new CustomClassLoader("/opt/classes/");
Class> clazz = loader.loadClass("com.example.MyClass");
Object instance = clazz.getDeclaredConstructor().newInstance();
| 方法 | 說明 | 是否可覆寫 | 建議 |
|---|---|---|---|
| loadClass() | 入口方法,實現雙親委派 | 可 (非 final) | 一般不覆寫,破壞委派模型 |
| findClass() | 實際查找類字節碼 | 可 (拋 CNFE) | 推薦覆寫此方法 |
| defineClass() | 字節碼轉 Class 對象 | final | JVM 內部實現,不可變 |
| findLoadedClass() | 查找已加載緩存 | final | 內部使用 |
類的唯一標識 = 全限定名 + 定義它的 ClassLoader。
同名類由不同加載器加載 → instanceof 失效、ClassCastException、靜態字段各自獨立。
opens/exports,反射深度受限掌握類加載機制,是排查類衝突、熱部署、框架原理分析、安全沙箱等高級問題的鑰匙。