子类初始化分两阶段:1. 类加载阶段执行父类静态块→子类静态块;2. 实例化阶段执行父类普通块→父类构造器→子类普通块→子类构造器。

子类初始化时,整个流程分两个明确阶段:类加载阶段(静态初始化)和对象实例化阶段(非静态初始化)。关键不是“谁先写谁先执行”,而是由 JVM 加载机制和构造调用链决定的。
类加载阶段:父类静态代码块 → 子类静态代码块
当首次用到子类(比如 new Son() 或访问子类静态成员),JVM 开始加载子类。但按「向上委托机制」,它必须先确保父类已加载。所以:
- 父类字节码被加载 → 执行父类中所有静态代码块(按书写顺序)
- 父类静态变量完成初始化(含显式赋值、静态块内赋值)
- 子类字节码被加载 → 执行子类中所有静态代码块(同样按书写顺序)
- 这个阶段只发生一次,且与是否创建对象无关
对象实例化阶段:父类普通代码块 → 父类构造方法 → 子类普通代码块 → 子类构造方法
真正执行 new Son() 时,才进入这一阶段。此时父类早已加载完毕,重点是对象的逐层构建:
- JVM 先为对象分配内存,并将所有字段初始化为默认值(如 int=0,Object=null)
- 隐式调用 super()(除非显式写了其他 super 或 this)→ 触发父类实例初始化
- 父类普通代码块(即非 static 的 {} 块)执行 → 给父类实例字段赋值或做预处理
- 父类构造方法体执行
- 回到子类:子类普通代码块执行 → 初始化子类自己的实例字段
- 子类构造方法体执行
为什么不能跳过父类静态块?
因为子类的字节码里可能直接引用父类的静态字段或方法。如果父类还没加载,这些引用就无法解析——JVM 会抛出 NoClassDefFoundError 或 IllegalAccessError。静态块本质是类加载过程中「初始化类变量」的时机,不是可选步骤。
一个容易忽略的细节:静态块里的 new 操作
如果父类静态块中写了 new Father(),会导致父类在加载阶段就触发一次实例化——此时父类静态块已执行完,但父类普通代码块和构造方法会立即运行。这种写法虽合法,但会让静态初始化和实例初始化交织,增加理解难度,一般应避免。

















