实例初始化块在各自构造方法中执行,父类块在super()后、父类构造体前执行,子类块在super()返回后、子类构造体前执行;其本质是编译器将块代码按序插入每个构造方法开头(super()之后)。

Java 中构造块(即实例初始化块)不会在子类构造方法调用前执行,而是在父类构造方法执行过程中、子类构造方法体开始执行之前完成——确切地说,它是在父类构造方法体中隐式插入执行的,且顺序严格遵循“先父类后子类、先静态后实例、先字段/块后构造方法”的初始化链。
构造块的实际执行时机
实例初始化块(非 static 的 { ... } 块)属于实例初始化的一部分,其执行时机绑定在构造方法内部:编译器会将每个实例初始化块的代码,按出现顺序“复制”到**每一个构造方法的开头**(在显式或隐式调用 super() 之后、构造方法其余代码之前)。
- 如果父类有实例初始化块,它会在父类构造方法体中被插入,在 super() 调用返回后立即执行
- 子类的实例初始化块则被插入到子类构造方法中,在 super() 执行完毕、子类自己的代码开始前执行
- 因此,父类构造块一定在子类构造块之前执行,但两者都发生在各自构造方法执行期间,而非“子类构造方法调用前”这个模糊时间点
执行顺序完整链条
以 new Child() 为例,实际执行流程如下:
- 触发 Child 类加载(若未加载),执行父类 Parent 的静态块 → 子类 Child 的静态块
- 进入 Child 构造方法,首先隐式或显式调用 super()
- 进入 Parent 构造方法:执行 super()(若 Parent 有父类则继续上溯),然后执行 Parent 的实例初始化块,再执行 Parent 构造方法剩余代码
- 回到 Child 构造方法:执行 Child 的实例初始化块,再执行 Child 构造方法剩余代码
一个直观示例
以下代码可验证执行顺序:
class Parent {
{ System.out.println("Parent init block"); }
public Parent() { System.out.println("Parent ctor"); }
}
class Child extends Parent {
{ System.out.println("Child init block"); }
public Child() { System.out.println("Child ctor"); }
}
// 输出:
// Parent init block
// Parent ctor
// Child init block
// Child ctor
可见:Parent 的构造块在 Parent 构造方法主体执行前完成;Child 的构造块在 Parent 构造方法完全返回后、Child 构造方法主体开始前执行——它不可能早于 super() 调用,更不会在“子类构造方法调用前”就运行。
常见误解澄清
有人误以为构造块像静态块一样在类加载时执行,或可在构造方法外独立触发。实际上:
- 实例初始化块只随每次 new 实例而执行,且仅一次,与构造方法强绑定
- 它不能绕过 super() 调用提前执行;若父类构造方法抛异常,子类构造块根本不会执行
- 多个实例块按源码顺序合并到同一位置,等效于按序拼接的语句
不复杂但容易忽略:构造块不是“预先执行”的钩子,而是编译器帮你自动注入构造方法的初始化逻辑,它的时序完全由构造调用链决定。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











