java类加载机制分加载、链接(含验证、准备、解析)、初始化三阶段:加载时生成class对象但未赋值;准备阶段为static变量分配内存并设默认值;初始化阶段才执行方法完成显式赋值和static块。

要真正理解 Java 类加载机制的三个阶段(加载、链接、初始化)和变量分配行为,最有效的方式是结合代码块执行顺序做分步验证。关键不在于背流程,而在于观察 JVM 何时为变量分配内存、何时赋值、何时执行代码——这些动作在字节码层面有明确对应,且能通过打印日志清晰呈现。
一、从 main 入口触发类加载,看清“加载→链接→初始化”三阶段
当 JVM 启动并执行 main 方法时,它首先加载包含 main 的类(如 Main)。这个过程不是一步到位的:
- 加载阶段:读取 Main.class 字节码,生成 Class 对象,但此时静态变量只占位(如 int 为 0,Object 为 null),尚未赋值;
- 链接之准备阶段:为所有 static 变量分配内存并设默认值(这是“分配”的实质发生点);
- 初始化阶段:才真正执行 static 变量显式赋值语句和 static{} 块——这才是“赋值”的起点。
例如:public static int x = 5; 中的 5 不是在准备阶段写入,而是在初始化阶段通过
二、用静态代码块 + 打印日志,定位初始化的实际时机
静态代码块是观察初始化阶段最直观的“探针”。它和静态变量初始化按源码书写顺序执行,且仅在类首次主动使用时运行一次:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 若 main 方法里只访问一个静态常量(如 public static final int VAL = 100;),JVM 可能跳过初始化(因编译期已内联);
- 但只要访问非 final 静态字段、调用静态方法、或 new 实例,就会强制触发初始化;
- 在 static{} 里打印日志,就能确认该类是否已进入初始化阶段——此时 所有 static 变量已完成默认分配(准备阶段),正进行显式赋值。
三、继承场景下拆解父类与子类的变量分配与执行流
有继承时,类加载机制会递归保障父类先行完成初始化:
- 第一次 new Child 时,JVM 发现 Parent 未初始化 → 先加载、链接、初始化 Parent(分配并赋值其 static 成员);
- 再回到 Child,完成其自身的 static 分配与初始化;
- 之后才开始实例化:先为 Parent 的实例变量分配内存(设默认值)、执行普通代码块、调用 Parent() 构造器;
- 最后才是 Child 实例变量分配、普通代码块、构造器。
注意:实例变量的“分配”发生在每次 new 时(堆中对象创建初期),而“赋值”紧随其后,在普通代码块和构造器之前完成。
四、组合关系揭示类加载的懒加载本质
一个类中声明另一个类的静态字段(如 public static Other other = new Other();),会触发 Other 的完整加载流程——但仅在此字段首次被读取时发生:
- 如果该字段从未被访问,Other.class 根本不会被加载;
- 一旦访问,JVM 立即加载、链接、初始化 Other,期间它的 static 块执行、static 变量赋值;
- 这说明类加载是“按需触发、严格隔离”的:每个类的初始化彼此独立,且只发生一次。
这种延迟性正是 JVM 优化启动速度和内存占用的核心机制之一。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










