验证和准备是类加载连接阶段的前两个子阶段,验证通过四层检查确保字节码合法安全,准备则为static字段分配内存并设默认值(编译期常量除外)。

Java 类加载过程中,验证和准备是连接阶段的前两个关键子阶段,它们紧随加载之后、解析之前发生,各自承担明确且不可替代的职责。
验证:四层检查确保字节码合法安全
验证不是形式主义,而是 JVM 对刚加载进方法区(Metaspace)的字节码做的深度“体检”,任一环节失败都会抛出 VerifyError 并中止类加载。它分四层递进执行:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
文件格式验证:确认魔数为
0xCAFEBABE、主次版本号在当前 JVM 支持范围内、常量池结构未损坏、无非法字节序列 -
元数据验证:检查类是否继承了
final类、是否实现抽象方法但未提供具体实现、字段与方法签名是否符合 Java 语义规范 - 字节码验证:分析每个方法的控制流图(CFG),确保跳转指令不越界、操作数栈不会上溢或下溢、局部变量类型始终匹配指令要求
-
符号引用验证:在解析前预先校验常量池中所有类、字段、方法的引用是否真实存在,且当前类具备访问权限(例如不能引用其他类的
private字段)
准备:为 static 字段分配内存并设零值
这个阶段只处理类变量(static 修饰的字段),不做任何逻辑执行,行为非常克制:
- 在方法区(JDK 8+ 为 Metaspace)为每个
static字段分配内存空间 - 将字段设为对应类型的默认值:
int→0、long→0L、boolean→false、引用类型→null - 不执行赋值语句,也不运行静态代码块;例如
public static int x = 5;中的5此时尚未写入,x的值仍是0 - 唯一例外是编译期常量:
public static final int MAX = 100;或public static final String NAME = "abc";,其值在编译时就写入常量池,准备阶段直接完成赋值
二者关系与常见误区
验证发生在准备之前,且两者均不依赖解析结果。验证是对字节码结构与语义的静态检查,准备则是纯粹的内存布局动作——既不读取常量池中的值,也不触发任何 Java 代码执行。开发者容易混淆的是把“赋默认值”当成“初始化”,其实真正的初始化(如执行 static { ... } 或 static int x = 5;)要等到初始化阶段由 <clinit></clinit> 方法完成。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










