Java继承中构造方法执行顺序由JVM强制规定:父类实例变量默认值→父类构造块→父类构造体→子类实例变量默认值→子类构造块→子类构造体,确保父类先完成初始化,子类字段在父类构造中访问时仍为默认值。

Java 继承关系中,构造方法执行顺序不是“由你决定怎么写”,而是 JVM 强制规定的初始化流水线。它直接决定字段有没有值、父类状态是否完整、子类字段是否被提前访问——稍有偏差,对象一出生就带病。
父类构造必须先完成,子类才能动
创建子类对象时,JVM 不允许跳过父类初始化。子类构造方法第一行(显式或隐式)必须调用 super() 或 this(),且 super() 会强制进入父类构造流程。这意味着:
- 父类的实例变量默认值已设(如 int=0、Object=null)
- 父类的构造代码块已全部执行完毕
- 父类构造方法体已运行结束
- 此时子类的实例变量仍为默认值(哪怕源码里写了
String name = "a";,也还没执行到那一步)
构造代码块在父类构造之后、子类构造之前插入
子类的构造代码块(即非 static 的 { } 块)不会在父类构造前运行,也不会等子类构造方法体开始才执行。它的准确位置是:父类构造方法返回后、子类构造方法体开始前。这个时机很关键:
- 子类字段已声明、内存已分配,this 可用
- 但子类字段显式赋值(如
id = generateId();)和构造代码块按源码顺序混合执行——谁写在前面,谁先发生 - 若父类构造中调用了被子类重写的方法,而该方法又读取了子类字段,拿到的一定是 null 或 0
静态部分只走一次,但必须父子分明
静态代码块和静态变量赋值属于类加载阶段,与对象无关,但顺序同样影响安全:
立即学习“Java免费学习笔记(深入)”;
- 哪怕只写
new Child(),JVM 也会先触发 Parent 类的静态初始化,再执行 Child 类的静态初始化 - 如果子类静态块依赖父类某个静态方法,而该方法又访问了子类尚未初始化的静态字段,就会出问题
- 静态块里不能访问任何实例成员,编译直接报错
字段初始化和构造块混排,顺序即逻辑
在子类中,这几件事是按源码书写顺序交替发生的:
- 子类实例变量默认值(自动)
- 子类字段显式赋值(如
status = "INIT";) - 子类第一个构造代码块({ ... })
- 子类第二个构造代码块(如有)
- 子类构造方法体(
this(...)或super(...)调用后)
比如你把 initCache(); 写在字段 cache 声明之前,编译器会报 “illegal forward reference”;反过来,把 cache = new HashMap(); 写在 initCache() 前面,就能安全调用。


















