本文深入探讨 Java 的类加载机制,包括双亲委派模型、类加载器的实现、破坏与绕过方式、源码实现与常见面试要点。
Java 源码 .java
被编译为 .class
文件后,并不会立即加载到 JVM 中,而是在运行时按需加载。
类的加载过程主要包括以下五个阶段:
Java 中类加载器主要分为以下三类:
java.*
核心类。ext
目录中的扩展类。classpath
下的类。也可通过继承 ClassLoader
来实现自定义类加载器。
双亲委派模型是一种类加载机制,其核心原则:
请求从子类加载器向上委托,只有父类加载器无法完成,才由子加载器尝试加载。
优点:
java.lang.Object
不被篡改)protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
// 1. 检查缓存
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ignore
}
// 2. 父类加载失败,尝试自己加载
if (c == null) {
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
通过重写 findClass
方法,可以自定义类加载逻辑。也可以故意跳过父类加载逻辑,从而破坏双亲委派机制。
public class MyClassLoader extends ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// 自定义类加载逻辑,如读取 class 文件字节码
return defineClass(name, bytecode, 0, bytecode.length);
}
}
注意:破坏机制虽灵活,但可能导致类冲突或安全问题。
Q1:什么是双亲委派模型?为什么需要它?
✅ A1:双亲委派模型是类加载器向上请求加载的机制,保证了系统类不会被篡改,提高安全性与稳定性。
Q2:如何实现一个破坏双亲委派机制的类加载器?
✅ A2:重写loadClass
方法,跳过parent.loadClass()
步骤,直接调用findClass()
即可。
Q3:为什么 Java 8 废弃永久代?
✅ A3:永久代容易内存泄漏,难以调优,Java 8 引入本地内存的 MetaSpace 更灵活。
-verbose:class
可查看类加载日志jvisualvm
、arthas
查看加载类信息类加载机制是 Java 动态性的根基,理解其加载流程、双亲委派模型与自定义加载器实现,对于架构设计与问题排查至关重要。
下一篇预告:《Java 并发模型:线程、锁与内存可见性机制详解》