静态代码块、普通代码块、构造方法的执行顺序
class B extends Object { static { System.out.println("Load B"); } public B() { System.out.println("Create B"); } } class A extends B { static { System.out.println("Load A"); } public A() { System.out.println("Create A"); } } public class Testclass { public static void main(String[] args) { new A(); } }
一、类加载阶段(静态初始化)
- 父类优先加载的原因Java类的加载遵循「向上委托机制」。当加载器尝试加载子类时,发现它继承自父类,会先确保父类已被加载(如果父类未被加载过)。底层逻辑:子类的字节码中可能直接引用父类的字段或方法,必须确保父类先存在。
- 静态代码块的执行顺序父类静态代码块 → 子类静态代码块只执行一次(类首次被加载时),且父类优先于子类。
- 发现
A
继承B
→ 先检查B
是否加载 - 加载
B
→ 执行B
的静态块(输出Load B
) - 加载
A
→ 执行A
的静态块(输出Load A
)
二、对象实例化阶段
(1) 实例初始化顺序
- 父类普通代码块 → 父类构造方法 → 子类普通代码块 → 子类构造方法
- 为什么父类优先?子类构造方法默认隐含super()调用(除非显式调用其他父类构造方法)。super()会触发父类构造方法的执行。
- 父类构造方法执行前会先执行父类的普通代码块。因为代码块用于给属性进行初始化。
(2) 详细流程(以 new A()
为例)
// 1. 父类B的实例初始化 B的普通代码块 → B的构造方法(输出`Create B`) // 2. 子类A的实例初始化 A的普通代码块 → A的构造方法(输出`Create A`)
注意:普通代码块在所属构造方法内的super()
之后执行,但在本类构造方法剩余代码之前执行。
三、完整顺序总结(继承关系)
- 类加载阶段父类静态块 → 子类静态块(只执行一次,优先级最高)
- 对象实例化阶段父类普通代码块 → 父类构造方法子类普通代码块 → 子类构造方法 (每次new都会执行)
四、其他的
1. 为什么父类加载完子类才能加载?
- 技术本质:子类的类结构(如方法表)依赖父类信息。
- JVM在解析子类时,需要确保父类的字段、方法等元数据已存在,否则无法正确构建子类的内存结构。
2. 为什么父类普通代码块先于子类执行?
- 构造方法链规则:子类构造方法必须通过
super()
调用父类构造方法。 - 父类构造方法执行前,会先执行父类的普通代码块(可以理解为父类构造方法的一部分)。