醋醋百科网

Good Luck To You!

说说类加载机制(类的加载机制)

一句话总结

类加载机制是JVM动态加载类的过程,包含加载、验证、准备、解析和初始化五个阶段。加载阶段读取.class文件生成Class对象;验证确保字节码合法;准备为静态变量分配内存并赋默认值;解析将符号引用转为直接引用;初始化执行静态代码块和变量赋值。各阶段顺序执行,确保类正确加载且符合安全规范。

详细解析

Java的类加载过程可以分为以下几个阶段,每个阶段都有其特定的任务和顺序:

1. 加载(Loading)

  • 任务:查找并加载类的二进制字节流(如.class文件),将类的静态存储结构转化为方法区的运行时数据结构,并在堆中生成一个代表该类的java.lang.Class对象。
  • 触发条件:当程序首次主动使用类时(如实例化对象、访问静态字段等)。
  • 类加载器启动类加载器(Bootstrap ClassLoader):加载JAVA_HOME/lib下的核心类库(如rt.jar)。扩展类加载器(Extension ClassLoader):加载JAVA_HOME/lib/ext下的扩展类。应用程序类加载器(Application ClassLoader):加载用户类路径(ClassPath)的类。自定义类加载器:用户可继承ClassLoader实现自定义加载逻辑(如热部署、模块化加载)。
  • 双亲委派模型:子类加载器优先委派父类加载器加载类,确保核心类库的安全性和唯一性。

2. 验证(Verification)

  • 任务:确保字节码符合JVM规范,防止恶意代码破坏虚拟机。
  • 验证内容文件格式验证:检查魔数(0xCAFEBABE)、版本号、常量池等。元数据验证:检查类继承、字段/方法访问权限、抽象类实现等是否符合语义。字节码验证:验证方法体中的指令逻辑(如操作数栈类型、跳转指令合法性)。符号引用验证:检查符号引用能否正确解析(如类、方法、字段是否存在)。

3. 准备(Preparation)

  • 任务:为类的静态变量分配内存并设置初始值(默认值,非代码中显式赋予的值)。
  • 示例
public static int value = 123;  // 准备阶段 value = 0,初始化阶段 value = 123
  • 注意:若字段被final修饰且为编译期常量(如public static final int VALUE = 123),则直接赋值到常量池,不经过准备阶段。

4. 解析(Resolution)

  • 任务:将常量池中的符号引用(Symbolic References)转换为直接引用(Direct References)。
  • 符号引用:以符号(如全限定名)描述引用的目标。
  • 直接引用:指向目标的指针、偏移量或句柄。
  • 解析目标:类/接口解析字段解析方法解析接口方法解析
  • 特点:解析阶段可能发生在初始化之后(支持动态绑定)。

5. 初始化(Initialization)

  • 任务:执行类构造器<clinit>()方法,完成静态变量赋值和静态代码块的执行。
  • 触发条件:主动引用类的五种场景:new实例化对象、访问类的静态字段(非final)或静态方法。反射调用类(如Class.forName("com.example.Test"))。初始化子类时,父类未初始化会先触发父类初始化。虚拟机启动时指定的主类(包含main()方法的类)。JDK7+的动态语言支持(如MethodHandle解析结果触发初始化)。
  • 线程安全:JVM保证<clinit>()方法在多线程环境下被正确加锁同步。

6. 类加载示例

class Parent {
    static int a = 1;
    static { System.out.println("Parent init"); }
}

class Child extends Parent {
    static int b = 2;
    static { System.out.println("Child init"); }
}

public class Main {
    public static void main(String[] args) {
        System.out.println(Child.b);  // 输出:Parent init → Child init → 2
    }
}
  • 执行过程:访问Child.b触发Child类的初始化。由于Child的父类Parent未初始化,先初始化Parent。父类Parent初始化完成后,再初始化子类Child。
控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言