java类变量在实例变量前初始化且仅一次,按源码顺序执行;实例变量每次new时按父类到子类、声明顺序初始化,默认值优先。

Java类变量(静态变量)总在实例变量之前初始化,且只执行一次;实例变量每次创建对象时都重新初始化,顺序严格按源码声明位置展开。真正决定行为的不是“谁更重要”,而是“谁属于类、谁属于对象”以及它们在代码中出现的先后。
类变量:加载时一次性执行,按源码顺序交错运行
类变量和static{}块在类首次被主动使用(如调用静态方法、访问静态字段、执行new)时触发,全局仅一次。它们不是“先全声明再全赋值”,而是按书写顺序逐行执行:
- 遇到
static int a = 1;,立即执行赋值 - 紧接着遇到
static { System.out.println("a=" + a); },此时a已是1 - 若块里引用了后面才声明的
static String s,s值为null(默认值),不是未定义错误 - 父类静态部分一定先于子类执行,哪怕你直接
new Child()——JVM强制先完成父类初始化
实例变量:每次new都重走一遍,父类优先、声明靠前优先
每次执行new MyClass(),JVM分配内存后立刻开始实例初始化流程,顺序固定:
- 先为所有实例字段设默认值(
int→0、Object→null) - 再按源码从上到下执行显式初始化(如
String name = getName();)和实例块{} - 实例块和字段初始化语句地位相同,编译后统一插入到每个构造器开头(
super()之后) - 若
name = getName()中调用了getName(),而该方法返回了尚未走到初始化步骤的age字段,则读到的是0,不是18
继承场景下的完整链条:像剥洋葱一样层层推进
以new Child()为例,实际执行流清晰分两段:
- 静态阶段(仅一次):Parent static → Child static
- 实例阶段(每次new都发生):Parent field → Parent block → Parent ctor → Child field → Child block → Child ctor
- 注意:
super()或隐式调用不改变变量初始化时机,只控制构造器链起点 - 子类构造器中调用可被重写的方法,该方法访问的子类字段可能还是默认值——这是空指针高频源头
验证与避坑建议:让初始化意图看得见、控得住
别猜执行顺序,用日志直接观察:
- 在静态变量右侧写
logAndReturn(42),而不是直接= 42 - 在实例字段、实例块、构造器中分别打印带标识的日志(如
"field A"、"block"、"ctor") - 静态变量尽量用常量或无副作用表达式初始化,避免调用需实例环境的方法
- 实例字段间有依赖时,不要靠声明顺序“碰运气”,移到构造器中统一处理更安全
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











