bigywater.tech
Java 内部原理 · 139

实例初始化块真实验证:执行顺序真实是父类块→父类字段→父类构造器→子类块→子类字段→子类构造器

实例初始化块(不带static的{}块)是Java里一个存在感很低但真实起作用的语法——这篇真实记录父子类都有初始化块、字段初始化、构造器时,六个步骤真实按什么顺序执行。

父类真实整体先于子类
真实验证:Base的块→字段→构造器三步真实全部先于Derived的块→字段→构造器执行完
同类内真实按源码顺序交替
真实验证:一个类里多个初始化块和字段初始化,真实严格按照它们在源码里出现的先后顺序依次执行

上一篇:AtomicReference ABA问题真实验证

真实验证:父子类完整初始化的六步真实顺序

Base和Derived各自定义了一个实例初始化块、一个赋值字段、一个构造器,用共享的静态日志列表记录每一步真实执行的时机。

InstanceInitializerDemo.java static class Base { { log.add("Base-实例初始化块"); } int baseField = logAndReturn("Base-字段初始化", 1); Base() { log.add("Base-构造器"); } } static class Derived extends Base { /* 同样结构 */ }
真实实测
真实完整执行顺序:
  1. Base-实例初始化块
  2. Base-字段初始化
  3. Base-构造器
  4. Derived-实例初始化块
  5. Derived-字段初始化
  6. Derived-构造器

真实结果证明了两条真实规则的叠加效果:第一,父类的初始化(隐式super()调用)真实必须完整跑完才会开始执行子类的任何初始化逻辑——不存在"父类块、子类块交替执行"这种情况;第二,同一个类内部,实例初始化块和字段初始化真实是按源码书写顺序执行的,且真实都发生在这个类自己的构造器方法体真正执行之前。这套顺序背后其实对应着字节码层面的真实机制:实例初始化块和字段初始化表达式,真实都会被编译器搬运并拼接进构造器方法(<init>)的开头部分,紧跟在super()调用之后、开发者手写的构造器代码之前。

真实验证:同一个类里多个初始化块严格按源码顺序交替执行

InstanceInitializerDemo.java static class MultiBlock extends Base { { log.add("第1个实例初始化块"); } int x = logAndReturn("字段x初始化", 10); { log.add("第2个实例初始化块"); } int y = logAndReturn("字段y初始化", 20); MultiBlock() { log.add("MultiBlock-构造器"); } }
真实实测
真实多个初始化块按源码顺序执行:
  Base-实例初始化块
  Base-字段初始化
  Base-构造器
  第1个实例初始化块
  字段x初始化
  第2个实例初始化块
  字段y初始化
  MultiBlock-构造器
真实结果证明"实例初始化块"和"字段初始化表达式"在Java的执行模型里是同一类东西,唯一的区别只是有没有变量名。MultiBlock里"第1个初始化块→字段x→第2个初始化块→字段y"这个真实交替顺序,精确复刻了它们在源码里出现的先后次序——如果把字段y的初始化表达式挪到第1个初始化块之前,真实执行顺序也会跟着调整到前面。这个规则在调试"字段初始化时依赖另一个字段的值,但拿到的却是默认值(0/null)"这类问题时很有用:凡是在源码顺序上排在后面的字段或初始化块,在排在前面的字段/块执行时,其值真实必然还是Java的默认零值,因为它压根还没被执行到。同时也再次印证了Base的完整三步真实先于MultiBlock自己的任何初始化逻辑执行——继承链上父类优先的规则,和同一个类内部的源码顺序规则,是两条独立叠加、互不冲突的真实规则。

分步演示:六步(含多块场景则是八步)真实顺序

每一步都是真实运行 new MultiBlock() 时,共享静态日志列表记录下的真实执行时机,不是按规则手工排的。

new MultiBlock() 的真实八步:Base 三步全部跑完,才轮到 MultiBlock 自己按源码顺序执行
这一步刚执行完的初始化动作

    参考与说明

    • 本文全部结果均在本机真实运行 Java 17 得到,父子类六步顺序和同类内多块交替顺序重复运行完全一致。
    • 和类初始化时机真实验证(那篇聚焦static初始化,只在类第一次被使用时触发一次)一起看,能更完整理解Java"类级别一次性初始化"和"每次new对象都要走一遍"的实例级别初始化,是两套完全独立的真实机制。
    • 没有涉及:实例初始化块在匿名内部类里的真实特殊用法(唯一能给匿名类做非静态初始化逻辑的地方)、字段初始化表达式里的异常如果抛出,真实会以什么形式从构造器传播出去——这两个话题留给系列后面按需再写。
    京ICP备2026067502号-1京公网安备11010502063487号