在 Java 中,一个类从被引入到最终可以使用,必须经历加载(Load)、链接(Link)和初始化(Initialize)这三个大阶段。你提到的 Locate 通常被包含在“加载”阶段中。
JVM 严格按照这个顺序来处理类,具体含义如下:
1. Locate & Load(定位与加载)
这是类生命周期的第一步,核心任务是把类的二进制字节流读入内存。
-
Locate(定位):类加载器根据类的全限定名(如
com.example.MyClass),在指定的路径下(如 ClassPath、网络、数据库或 JAR 包中)找到对应的.class文件。 -
Load(加载):将找到的字节流读入内存,并在方法区(Method Area)创建一块内存区域,存储类的元数据(如类的结构、字段、方法定义、常量池等)。同时在堆区生成一个代表这个类的
java.lang.Class对象,作为方法区中该类的数据访问入口。
2. Link(链接)
加载完成后,类还不能直接使用,必须经过链接阶段进行校验和准备。链接阶段又细分为三个子步骤:
- Verify(验证):检查加载进来的字节码是否符合 JVM 规范,是否安全。例如:文件格式是否正确、是否有恶意的跳转指令、类型转换是否合法等。这一步是为了防止恶意代码破坏 JVM。
-
Prepare(准备):为类的静态变量分配内存,并设置零值(如
int设为 0,引用类型设为null)。注意:这里不包括实例变量(它们在对象实例化时才分配),也不包括赋了初始值的静态变量(真正的赋值在初始化阶段)。 - Resolve(解析):将常量池内的符号引用(如字符串形式的类名、方法名)替换为直接引用(如指向内存中具体对象的指针)。
3. Initialize(初始化)
这是类加载的最后一步,也是真正执行 Java 代码的阶段。
-
执行
<clinit>方法:JVM 会执行编译器自动生成的<clinit>(类构造器)方法。这个方法包含了所有静态变量的显式赋值语句和静态代码块(static {}),并且按照它们在源码中出现的顺序自上而下执行。 -
触发条件:初始化不是随时发生的,只有在遇到特定情况时才会触发(例如:首次
new对象、读取或写入静态变量、调用静态方法、反射调用、初始化子类时等)。