java变量初始化顺序由jvm严格控制:先静态后实例,先父类后子类,按源码声明顺序执行;静态部分在类首次主动使用时执行一次,实例部分每次new时从父到子逐层初始化,构造器内调用重写方法存在未初始化风险。

Java 变量初始化顺序不是随意发生的,而是由 JVM 严格控制的确定性流程。理解它能帮你避开空指针、意外默认值、构造器中方法调用失效等常见陷阱。
静态成员:类加载时一次性执行
静态变量和静态代码块在类**首次被主动使用**(比如 new 实例、调用静态方法、访问非 final 静态字段)时触发,且只执行一次。它们按源码中出现的顺序交错执行:遇到静态变量就赋值,遇到 static {} 就立即运行。
- 父类静态部分一定先于子类执行,哪怕子类先被引用
- 静态字段在“准备阶段”已设默认值(如 int=0、Object=null),真正赋值发生在“初始化阶段”
- 可向前赋值但不可向前读取——静态代码块里能给后面声明的 static 变量赋值,但不能打印它
实例成员:每次 new 时从父到子逐层展开
每创建一个对象,JVM 分配内存后立刻开始实例初始化,顺序固定:
- 先父类:按源码顺序执行父类的实例变量显式赋值 + 非静态代码块(即 {} 块)
- 再父类构造方法体(此时 super() 已完成)
- 然后子类:同样按声明顺序执行实例变量赋值 + 非静态代码块
- 最后执行子类构造方法体
注意:非静态代码块和字段初始化语句地位等同,编译后会被合并插入到每个构造方法开头(super() 之后),所以总在构造方法逻辑之前运行。
继承场景下的完整链条示例
以 new Child() 为例,整个过程像剥洋葱:
- Grandparent 静态变量 → Grandparent 静态代码块
- Parent 静态变量 → Parent 静态代码块
- Child 静态变量 → Child 静态代码块
- Grandparent 实例变量 → Grandparent 非静态代码块 → Grandparent 构造方法
- Parent 实例变量 → Parent 非静态代码块 → Parent 构造方法
- Child 实例变量 → Child 非静态代码块 → Child 构造方法
构造函数里的关键提醒
构造器是初始化的最后一步,但它不是“安全区”:
- 避免在构造器中调用可被子类重写的方法——此时子类实例变量尚未初始化,可能仍为默认值(如 null 或 0)
- 若构造器内调用了某个方法,而该方法访问了尚未执行到的实例变量,结果就是未预期的默认值
- final 字段必须在构造器结束前完成赋值,否则编译报错
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











