JVM 类加载机制概述
JVM 类加载机制是 Java 虚拟机将类文件(.class)加载到内存,并进行验证、准备、解析和初始化的过程。这一机制确保了类的正确性和安全性,同时支持动态加载和运行时绑定。
JVM 类加载器的种类
JVM 类加载器分为以下三种主要类型,它们共同构成类加载的层次结构:
启动类加载器(Bootstrap ClassLoader)
负责加载 Java 核心类库(如 rt.jar ,加载java.lang、java.util 等),位于 JAVA_HOME/lib 目录下的核心类。由 C++ 实现,是 JVM 的一部分,无法在 Java 代码中直接引用。
扩展类加载器(Extension ClassLoader)
继承自 java.lang.ClassLoader,负责加载 JAVA_HOME/lib/ext 目录或 java.ext.dirs 系统变量指定路径下的扩展类库。由 sun.misc.Launcher$ExtClassLoader 实现。
应用程序类加载器(Application ClassLoader)
也称为系统类加载器(System ClassLoader),负责加载用户类路径(ClassPath)下的类。由 sun.misc.Launcher$AppClassLoader 实现,是默认的类加载器。
自定义类加载器
用户可通过继承 java.lang.ClassLoader 类实现自定义类加载器,用于特定场景(如热部署、模块化加载等)。需重写 findClass() 方法,而非 loadClass() 以避免破坏双亲委派模型。
示例:
public class CustomClassLoader extends ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] classData = loadClassData(name); // 从自定义路径加载字节码
return defineClass(name, classData, 0, classData.length);
}
private byte[] loadClassData(String className) {
// 实现从文件或网络加载字节码的逻辑
}
}
类加载的触发条件
类加载通常在以下情况下触发:
- 创建类的实例(
new操作) - 访问类的静态变量或静态方法
- 使用反射(
Class.forName()) - 初始化子类时触发父类加载
- JVM 启动时加载主类(包含
main方法的类)
类加载的五个阶段
加载(Loading)
- 通过类的全限定名获取类的二进制字节流。
- 将字节流转换为方法区的运行时数据结构。
- 在堆中生成一个
java.lang.Class对象,作为方法区数据的访问入口。
验证(Verification)
- 确保类文件的格式正确且符合 JVM 规范。
- 包括文件格式验证、元数据验证、字节码验证和符号引用验证。
- 防止恶意代码或损坏的类文件影响 JVM 运行。
准备(Preparation)
- 为类的静态变量分配内存并设置初始值(零值)。
- 例如
static int a = 5在准备阶段会被初始化为0,而非5。 - 如果静态变量是常量(
final),则直接赋值为目标值。
解析(Resolution)
- 将符号引用替换为直接引用。
- 符号引用是类、方法或字段的描述信息,直接引用是具体的内存地址。
- 解析可以在初始化阶段之后进行(延迟解析)。
初始化(Initialization)
- 执行类的静态代码块(
static {})和静态变量的显式赋值。 - 是类加载的最后一步,JVM 确保多线程环境下初始化仅执行一次。
类加载器模型(ClassLoader)
双亲委派模型
- 类加载器在加载类时先委托父加载器尝试加载。
- 父加载器无法完成时,子加载器才会尝试加载。
- 避免重复加载,确保核心类库的安全性。
破坏双亲委派模型
某些场景需要打破双亲委派模型:
- SPI(Service Provider Interface):如 JDBC 驱动加载,核心类库(如
java.sql.Driver)由启动类加载器加载,但具体实现(如 MySQL 驱动)需由应用类加载器加载。 - OSGi:模块化框架中,每个模块有独立的类加载器,支持动态加载和卸载。
常见问题与排查
类加载失败
ClassNotFoundException:类未找到,通常是类路径配置错误。NoClassDefFoundError:类加载时成功,但运行时依赖的类缺失。(本地跑case 的时候经常遇到)
类冲突
- 实际开发过程中遇到多版本类库冲突,可通过调整类加载顺序或使用隔离机制(如 Maven Shade)解决。
1390

被折叠的 条评论
为什么被折叠?



