Java变量初始化由JVM按阶段和代码位置严格驱动:静态内容优先、父类在前、同级依源码顺序;静态变量与块类加载时执行一次且交错运行;实例变量与块每次new时按继承链和声明顺序执行;构造器是终点但易引发未初始化访问;成员变量有默认值,局部变量必须显式初始化。

Java变量初始化不是靠“谁更重要”来排先后,而是由JVM按阶段和代码位置严格驱动:静态内容先跑、父类必须在前、同级看源码顺序。搞清这个逻辑,比背口诀更能避开空指针、默认值误用和构造器中调用重写方法引发的诡异行为。
静态变量与静态块:类加载时只执行一次,且交错运行
静态成员(static字段和static{}块)在类首次被主动使用(比如调用静态方法、访问静态字段、执行new)时触发,整个过程只发生一次。
- 它们按源码从上到下交错执行:遇到一个静态变量就初始化,紧接着遇到静态块就运行,再下一个静态变量……
- 如果静态块里引用了后面才声明的静态变量,该变量此时仍是默认值(如
int为0,Object为null) - 父类静态部分一定先于子类执行——哪怕你直接
new子类,JVM也会先完成父类的静态初始化 - 编译期常量(如
public static final int MAX = 100;)不触发类初始化,直接内联
实例变量与实例块:每次new都重走一遍,按继承链+声明顺序执行
每次创建对象时,JVM分配内存后立即开始实例初始化,顺序固定:
- 先父类:按源码顺序执行父类的实例变量赋值 + 实例块(
{}),再执行父类构造器 - 再子类:同样顺序执行子类的实例变量赋值 + 实例块,最后执行子类构造器
- 实例块和字段初始化语句地位相同,编译后统一插入到每个构造器开头(
super()之后) - 若字段初始化表达式中调用了本类方法,该方法访问的其他实例变量可能还没走到显式赋值步骤,仍为默认值(如
int为0)
构造器是收尾环节,但容易埋雷
构造器本身不参与变量初始化,它只是整个流程的终点。此时变量虽已就位,但有两点关键风险:
立即学习“Java免费学习笔记(深入)”;
- 构造器中调用可被子类重写的方法,而该方法又访问子类的实例变量——此时子类字段尚未初始化,读到的是默认值
-
this()或super()必须是构造器第一条语句,但它不改变变量初始化时机,只决定构造器链起点 - 避免在构造器中做复杂逻辑或跨对象依赖,尤其不要在初始化未完成时发布
this引用
局部变量必须显式初始化,成员变量有默认值
这是常被忽略的基础差异:
- 成员变量(字段)无论是否赋值,JVM都会赋予默认值:
int→0,boolean→false,引用类型→null - 局部变量没有默认值,使用前必须显式赋值,否则编译报错
- 包装类型(如
Integer)作为成员变量默认为null,解包时易抛NullPointerException - 字段间相互依赖时,务必注意声明顺序——靠后的字段不能被前面的初始化表达式安全引用


















