4.Java 类加载机制
·
4.Java 类加载机制
- 一、类加载机制概述
- 1. 类加载的定义
- 类加载是指将类的字节码文件(.class 文件)加载到 JVM 中,并在内存中生成对应的 Class 对象的过程。
- 类加载是 JVM 执行 Java 程序的第一步。
- 2. 类加载的时机
- 类的加载是动态的,JVM 不会一次性加载所有类,而是在需要时才会加载。
- 以下情况会触发类的加载:
- 创建类的实例(new 关键字)。
- 访问类的静态变量或静态方法。
- 反射调用(如 Class.forName())。
- 初始化子类时,父类会被优先加载。
- JVM 启动时,包含 main() 方法的类会被加载。
- 1. 类加载的定义
- 二、类加载的过程
- 类加载的过程分为以下三个阶段:
- (1)加载(Loading)
- (2)链接(Linking)
- (2.1)验证(Verification)
- (2.2)准备(Preparation)
- (2.3)解析(Resolution)
- (3)初始化(Initialization)
- 1. 加载(Loading)
- 任务 :
- 通过类的全限定名(Fully Qualified Name)获取类的字节码文件(.class 文件)
- 将字节码文件加载到内存中,并生成对应的 Class 对象。
- 加载来源 :
- 本地文件系统。
- 网络(如 Applet)。
- JAR 包或 WAR 包。
- 动态生成(如动态代理)。
- 加载结果 :
- 在 方法区 生成类的运行时数据结构(如 类信息、字段、方法 等)。
- 在 堆 中生成 Class 对象 ,作为方法区数据的访问入口。
- 任务 :
- 2. 链接(Linking)
- 2.1 验证(Verification) :
- 检查字节码文件的正确性,确保符合 JVM 规范。
- 包括 文件格式验证 、 元数据验证 、 字节码验证 等。
- 2.2 准备(Preparation) :
- 为类的 静态变量分配内存 ,并 设置默认值 (如 0、null 等)。
- 如果静态变量是常量( final ),则直接赋值为初始值。
- 2.3 解析(Resolution) :
- 将常量池中的 符号引用 (Symbolic Reference)转换为 直接引用 (Direct Reference)。
- 符号引用:类的全限定名、字段名、方法名等。
- 直接引用:指向内存中具体地址的指针。
- 2.1 验证(Verification) :
- 3. 初始化(Initialization)
- 任务 :
- 执行类的静态代码块(static {})和静态变量的赋值操作。
- 触发条件 :
- 类被首次主动使用时(如创建实例、访问静态变量等)。
- 注意事项 :
- 父类的初始化优先于子类。
- 如果类已经初始化过,则不会重复初始化。
- 任务 :
- 三、类加载器
- 1. 类加载器的分类
- 3.1 启动类加载器(Bootstrap Class Loader) :
- 加载 JVM 核心类库 (如 rt.jar)。
- 由 C++ 实现,是 JVM 的一部分。
- 3.2 扩展类加载器(Extension Class Loader) :
- 加载
JAVA_HOME/lib/ext目录下的类库。
- 加载
- 3.3 应用程序类加载器(Application Class Loader) :
- 加载用户类路径(
ClassPath)上的类。
- 加载用户类路径(
- 3.4 自定义类加载器(Custom Class Loader) :
- 用户自定义的类加载器,继承
ClassLoader类。
- 用户自定义的类加载器,继承
- 3.1 启动类加载器(Bootstrap Class Loader) :
- 2. 双亲委派模型
- 原理 :
- 类加载器在加载类时,首先委托父类加载器加载。
- 如果父类加载器无法加载,则由子类加载器尝试加载。
- 优点 :
- 避免类的重复加载。
- 保证核心类库的安全性。
- 原理 :
- 3. 打破双亲委派模型
- 场景 :
- SPI(Service Provider Interface)机制(如 JDBC)。
- 热部署(Hot Deployment)。
- 实现方式 :
- 重写
**ClassLoader**的loadClass()方法。
- 重写
- 场景 :
- 1. 类加载器的分类
- 四、类加载的异常
- 1.
**ClassNotFoundException**- 原因 :
- 类加载器无法找到指定的类。
- 常见场景 :
- 类路径配置错误。
- 类文件缺失。
- 原因 :
- 2.
**NoClassDefFoundError**- 原因 :
- 类加载器找到了类,但在链接阶段失败。
- 常见场景 :
- 类的依赖缺失。
- 类的静态初始化失败。
- 原因 :
- 1.
- 五、自定义类加载器
- 1. 实现步骤
- 继承
ClassLoader类。 - 重写
findClass()方法。 - 调用
defineClass()方法将字节码转换为 Class 对象。
- 继承
- 2. 使用场景
- 动态加载类(如插件化开发)。
- 热部署。
- Java的类加载机制允许在运行时加载类,默认情况下,类一旦被加载,除非重新启动JVM,否则无法卸载或重新加载。自定义类加载器可以绕过这一限制,通过创建新的类加载器实例来加载更新后的类,从而实现热部署。
- 加密类文件。
- 1. 实现步骤
- 六、类加载机制的实践
- 1. 查看类加载器
- 示例代码:
-
ClassLoader loader = MyClass.class.getClassLoader();
- 2. 自定义类加载器
- 1. 查看类加载器
public class MyClassLoader extends ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] data = loadClassData(name);
return defineClass(name, data, 0, data.length);
}
private byte[] loadClassData(String name) {
// 从文件或网络加载字节码
return null;
}
}
更多推荐



所有评论(0)