4.Java 类加载机制

  • 一、类加载机制概述
    • 1. 类加载的定义
      • 类加载是指将类的字节码文件(.class 文件)加载到 JVM 中,并在内存中生成对应的 Class 对象的过程。
      • 类加载是 JVM 执行 Java 程序的第一步。
    • 2. 类加载的时机
      • 类的加载是动态的,JVM 不会一次性加载所有类,而是在需要时才会加载。
      • 以下情况会触发类的加载:
        • 创建类的实例(new 关键字)。
        • 访问类的静态变量或静态方法。
        • 反射调用(如 Class.forName())。
        • 初始化子类时,父类会被优先加载。
        • JVM 启动时,包含 main() 方法的类会被加载。
  • 二、类加载的过程
    • 类加载的过程分为以下三个阶段:
    • (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)。
        • 符号引用:类的全限定名、字段名、方法名等。
        • 直接引用:指向内存中具体地址的指针。
    • 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 类。
    • 2. 双亲委派模型
      • 原理
        • 类加载器在加载类时,首先委托父类加载器加载。
        • 如果父类加载器无法加载,则由子类加载器尝试加载。
      • 优点
        • 避免类的重复加载。
        • 保证核心类库的安全性。
    • 3. 打破双亲委派模型
      • 场景
        • SPI(Service Provider Interface)机制(如 JDBC)。
        • 热部署(Hot Deployment)。
      • 实现方式
        • 重写 **ClassLoader**loadClass() 方法。
  • 四、类加载的异常
    • 1. **ClassNotFoundException**
      • 原因
        • 类加载器无法找到指定的类。
      • 常见场景
        • 类路径配置错误。
        • 类文件缺失。
    • 2. **NoClassDefFoundError**
      • 原因
        • 类加载器找到了类,但在链接阶段失败。
      • 常见场景
        • 类的依赖缺失。
        • 类的静态初始化失败。
  • 五、自定义类加载器
    • 1. 实现步骤
      • 继承 ClassLoader 类。
      • 重写 findClass() 方法。
      • 调用 defineClass() 方法将字节码转换为 Class 对象。
    • 2. 使用场景
      • 动态加载类(如插件化开发)。
      • 热部署。
        • Java的类加载机制允许在运行时加载类,默认情况下,类一旦被加载,除非重新启动JVM,否则无法卸载或重新加载。自定义类加载器可以绕过这一限制,通过创建新的类加载器实例来加载更新后的类,从而实现热部署。
      • 加密类文件。
  • 六、类加载机制的实践
    • 1. 查看类加载器
      • 示例代码:
      • ClassLoader loader = MyClass.class.getClassLoader();

    • 2. 自定义类加载器
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;
    }
}

更多推荐