对象创建的底层流水线分静态与实例两阶段:类加载时执行父类静态块→子类静态块;每次new时执行父类普通块→父类构造→子类普通块(含成员变量初始化)→子类构造,全程单向确定、不可并发。

要真正理解对象变量生成的底层流水线,关键不是背顺序,而是用构造块和构造方法的执行时机去“拆解”一次实例化动作——就像把一个工厂流水线逐站观察。
静态部分:类加载时只跑一次
静态代码块和静态变量初始化属于类级别,发生在类第一次被主动使用(如 new、调用静态方法、访问静态字段)前。它们按源码中出现的先后顺序执行,父类优先于子类。
- 父类静态块 → 子类静态块
- 静态变量赋值语句与静态块地位等同,谁在前面谁先执行
- 这个阶段不涉及任何对象,内存里还没有实例,只有 Class 对象和 static 字段
实例部分:每次 new 都走一遍的初始化链
当执行 new SubClass() 时,JVM 在堆中分配空间后,立刻开始填充这个新生对象。此时执行顺序严格固定:
- 父类普通代码块(非 static)→ 父类构造方法
- 子类普通代码块 → 子类构造方法
- 注意:成员变量初始化(如 Rmb r = new Rmb();)就插在对应类的普通代码块之前,但仍在构造方法调用前
也就是说,成员变量声明处的初始化表达式,本质上是被编译器悄悄挪进了普通代码块的位置。它不是“声明即执行”,而是在对象内存已分配、字段默认值(0/null/false)已设好之后,紧挨着普通代码块执行。
实战验证:三行代码看清流水线
写一个父子类,每个关键位置加一句打印,就能清晰看到执行流:
- 父类静态块 → 输出 “Fu static”
- 子类静态块 → 输出 “Zi static”
- 父类普通块 → 输出 “Fu init block”
- 父类构造方法 → 输出 “Fu ctor”
- 子类普通块(含成员变量 new)→ 输出 “Zi init block” 和 “Rmb is construct”
- 子类构造方法 → 输出 “Zi ctor”
输出顺序就是对象诞生的真实时间轴,没有跳步,也没有并发——它是一条单向、确定、可复现的初始化流水线。
为什么 this() 和 super() 必须在第一行
因为 JVM 要确保父类构造完成,子类才能安全访问自身字段或调用本类方法。如果允许在中间插入逻辑,就可能在父类尚未初始化完毕时,读取到未定义的子类字段值(比如 this.name 还是 null)。所以语法强制把委托和继承调用放在最前,本质是为这条流水线“锁住起点”。

















