欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 产业 > JVM 类加载 详解

JVM 类加载 详解

2024/12/3 20:18:29 来源:https://blog.csdn.net/T_Y_F_/article/details/144196894  浏览:    关键词:JVM 类加载 详解

JVM 类加载详解

JVM 类加载(Java Class Loading) 是 Java 虚拟机 (JVM) 执行 Java 程序的重要机制之一,用于将 .class 文件动态加载到内存中并进行验证、解析和初始化,最终生成可以直接使用的类对象。


1. 类加载的基本概念

1.1 什么是类加载?

类加载是将 .class 文件加载到 JVM 并转化为内存中可以运行的类的过程。

  • 目标:生成一个内存中的 Class 对象,供程序使用。
  • 触发点
    • 当程序首次访问类或接口时(如创建对象、访问静态字段或调用静态方法)。
    • 通过反射加载类(如 Class.forName)。
    • 动态代理生成的类。

1.2 类加载的三阶段

  1. 加载(Loading):
    • .class 文件加载到内存中,生成 Class 对象。
  2. 链接(Linking):
    • 将类的二进制数据合并到 JVM 中。
      • 验证:检查类文件的合法性。
      • 准备:为类的静态变量分配内存,并设置默认初始值。
      • 解析:将类、方法、字段的符号引用解析为直接引用。
  3. 初始化(Initialization):
    • 执行类的初始化逻辑,包括静态变量的赋值和静态代码块的执行。

2. JVM 类加载机制

JVM 的类加载遵循 双亲委派模型运行时动态加载 的原则。

2.1 双亲委派模型

定义

类加载时会先委托父加载器加载,只有当父加载器无法加载时,才由当前加载器尝试加载。

过程
  1. 一个类加载请求从当前类加载器开始。
  2. 如果当前加载器存在父加载器,优先交给父加载器处理。
  3. 如果父加载器无法加载,则由当前加载器加载。
优点
  • 安全性:防止重复加载,保证核心类不被篡改。
  • 统一性:确保 Java 的基础类库(如 java.lang.String)使用同一个加载器加载。

2.2 类加载器

JVM 的主要类加载器
  1. 启动类加载器(Bootstrap ClassLoader)

    • 负责加载 JVM 的核心类库,如 rt.jar
    • 用 C/C++ 实现,直接由 JVM 内部调用。
  2. 扩展类加载器(Extension ClassLoader)

    • 加载 JAVA_HOME/lib/ext 目录下的扩展类库。
  3. 应用类加载器(App ClassLoader)

    • 加载应用程序的类路径(CLASSPATH)下的类。
  4. 自定义类加载器(Custom ClassLoader)

    • 用户可以通过继承 ClassLoader 自定义类加载器。
类加载器之间的关系
  • 启动类加载器是最顶层的加载器,扩展类加载器和应用类加载器是其子加载器。
  • 自定义类加载器通常由应用类加载器加载。

3. 类加载的流程

以下是类加载的主要流程及每个阶段的作用:

3.1 加载阶段

  • 功能:将 .class 文件加载到内存中,生成 Class 对象。
  • 操作
    1. 通过类的全限定名找到对应的 .class 文件。
    2. .class 文件的字节流读入内存。
    3. 将字节流解析为 Class 对象。

3.2 链接阶段

  1. 验证

    • 确保 .class 文件符合 Java 规范,保证字节码的合法性。
    • 检查:
      • 魔数和版本号。
      • 常量池中符号的正确性。
      • 字节码指令是否正确。
  2. 准备

    • 为静态变量分配内存,并设置默认初始值(如 0null)。
    • 示例:
      public static int a = 10;
      
      在准备阶段,a 的值为 0,赋值为 10 在初始化阶段完成。
  3. 解析

    • 将常量池中的符号引用(如方法名、字段名)替换为直接引用(内存地址)。

3.3 初始化阶段

  • 触发点
    • 主动使用类(如实例化对象、调用静态方法)。
  • 操作
    • 初始化静态变量。
    • 执行静态代码块。

4. 类加载的类型

根据触发类加载的时机,类加载分为以下两种类型:

4.1 主动引用

以下情况会触发类的加载:

  1. 创建类的实例。
  2. 访问类的静态字段。
  3. 调用类的静态方法。
  4. 通过反射调用类。
  5. 初始化类的子类。

示例:

class Demo {static {System.out.println("Demo类被初始化");}
}
public class Main {public static void main(String[] args) {Demo demo = new Demo(); // 主动触发}
}

4.2 被动引用

以下情况不会触发类的加载:

  1. 通过子类调用父类的静态字段。
  2. 定义类的数组。
  3. 引用类的常量。

示例:

class Parent {static {System.out.println("Parent类被初始化");}public static int value = 42;
}class Child extends Parent {static {System.out.println("Child类被初始化");}
}public class Main {public static void main(String[] args) {System.out.println(Child.value); // 只触发父类加载}
}

5. 类加载的关键点

5.1 类加载器的双亲委派机制

  • 原理:父加载器优先加载,确保基础类不被重复加载。
  • 示例
ClassLoader loader = Demo.class.getClassLoader();
System.out.println(loader);                   // AppClassLoader
System.out.println(loader.getParent());       // ExtClassLoader
System.out.println(loader.getParent().getParent()); // null (Bootstrap)

5.2 自定义类加载器

  • 自定义类加载器通常用于加载加密的类文件或特殊格式的类文件。

实现示例

public class CustomClassLoader extends ClassLoader {@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {byte[] classData = loadClassData(name);return defineClass(name, classData, 0, classData.length);}private byte[] loadClassData(String name) {// 加载类文件的字节流return new byte[0]; // 示例中省略实际加载逻辑}
}

6. 类加载的示例

6.1 静态字段与静态代码块

class Demo {static int value = 10;static {System.out.println("静态代码块执行");value = 20;}
}
public class Main {public static void main(String[] args) {System.out.println(Demo.value); // 输出: 静态代码块执行 20}
}

6.2 动态加载类

public class Main {public static void main(String[] args) throws Exception {Class<?> clazz = Class.forName("com.example.Demo");Object obj = clazz.getDeclaredConstructor().newInstance();System.out.println(obj.getClass().getName());}
}

7. 类加载的优缺点

7.1 优点

  1. 延迟加载:提高系统启动效率。
  2. 动态扩展:支持动态加载类,增强灵活性。
  3. 隔离性:不同的类加载器可以隔离命名空间,避免冲突。

7.2 缺点

  1. 性能开销:加载类时需要额外的资源。
  2. 复杂性:双亲委派机制增加调试难度。

8. 总结

  • 核心机制:类加载是 JVM 将 .class 文件转化为可运行代码的关键环节,主要包括加载、链接和初始化三阶段。
  • 双亲委派模型:确保类加载的安全性和统一性。
  • 动态性:支持运行时加载和动态代理等功能。
  • 实际应用:常见于自定义类加载器、插件系统和框架设计中。

深入理解类加载机制,可以
帮助开发者更好地调优 JVM,设计更灵活的应用程序。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com