类加载阶段只执行静态内容且父类优先,对象创建阶段才执行构造代码块和构造方法;具体为:父类静态变量→父类静态块→子类静态变量→子类静态块→父类实例变量默认值→父类构造块与显式赋值→父类构造方法→子类实例变量默认值→子类构造块与显式赋值→子类构造方法。

类加载阶段不执行构造方法,只处理静态内容;父类静态部分必须先完成,子类静态部分才开始,这是JVM双亲委派机制强制保障的。
类加载阶段:只跑静态,且严格父→子
类加载发生在类首次被主动使用时(比如第一次 new、调用静态方法、访问静态字段),此时JVM只做“准备类”,不创建对象,因此构造代码块和构造方法完全不参与这个阶段。真正执行的只有:
- 父类静态变量(按声明顺序)→ 父类静态代码块(按书写顺序)
- 子类静态变量(按声明顺序)→ 子类静态代码块(按书写顺序)
这个顺序不可跳过或颠倒。哪怕你只写 new Child(),JVM也会先确保 Parent.class 已加载并完成全部静态初始化,再继续加载 Child.class。静态内容全程只执行一次,后续无论 new 多少次、调用多少次静态方法,都不会重复。
对象创建阶段:构造块与构造方法才登场
真正涉及构造代码块(即非 static 的 {} 块)和构造方法的,是每次 new 对象时的实例初始化流程,它和类加载阶段分离、独立运行。顺序固定为:
立即学习“Java免费学习笔记(深入)”;
- 父类实例变量默认值(如 int→0,Object→null)
- 父类构造代码块 + 实例变量显式赋值(按源码顺序交替执行)
- 父类构造方法体(前提是 super() 已调用,隐式或显式)
- 子类实例变量默认值
- 子类构造代码块 + 实例变量显式赋值(同样按源码顺序)
- 子类构造方法体
注意:构造代码块不是“独立模块”,它被编译器自动插入到每个构造方法开头、super() 调用之后的位置,所以必然在父类构造方法返回后才执行子类的构造块。
怎么验证这两阶段的联动?
加日志是最直接的方式,重点观察触发时机:
- 在所有 static 块里打印 “static in X” —— 这些只在第一次 new 或首次访问静态成员时输出一次
- 在所有构造代码块里打印 “init block in X” —— 每次 new 都会输出,且总在对应构造方法之前
- 在构造方法里打印 “ctor in X” —— 它一定晚于同级的构造代码块,且父类 ctor 总比子类早
如果发现某个 static 日志重复出现,说明触发了多次类加载(比如不同类加载器加载了同一类);如果构造块日志没按父→子出现,大概率是子类构造方法里没把 super() 放在第一行(编译会报错,所以通常不会发生)。
常见误区提醒
容易混淆的点在于把“类加载”和“对象创建”混为一谈:
- 静态代码块 ≠ 构造代码块:前者属类,后者属对象
- 父类构造方法执行,不代表父类已“加载完毕”——它早在 new 之前就完成了静态初始化
- 子类静态块里能安全读取父类 public static 字段,但父类静态块不能依赖子类任何静态状态(编译期就检查)


















