静态代码块、普通代码块、构造方法的执行顺序

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();
    }
}

一、类加载阶段(静态初始化)

  1. 父类优先加载的原因Java类的加载遵循「向上委托机制」。当加载器尝试加载子类时,发现它继承自父类,会先确保父类已被加载(如果父类未被加载过)。底层逻辑:子类的字节码中可能直接引用父类的字段或方法,必须确保父类先存在。
  2. 静态代码块的执行顺序父类静态代码块 → 子类静态代码块只执行一次(类首次被加载时),且父类优先于子类。
  3. 发现A继承B → 先检查B是否加载
  4. 加载B → 执行B的静态块(输出Load B
  5. 加载A → 执行A的静态块(输出Load A

二、对象实例化阶段

(1) 实例初始化顺序

  1. 父类普通代码块 → 父类构造方法 → 子类普通代码块 → 子类构造方法
  2. 为什么父类优先?子类构造方法默认隐含super()调用(除非显式调用其他父类构造方法)。super()会触发父类构造方法的执行。
  3. 父类构造方法执行前会先执行父类的普通代码块。因为代码块用于给属性进行初始化。

(2) 详细流程(以 new A() 为例)

// 1. 父类B的实例初始化
B的普通代码块 → B的构造方法(输出`Create B`)
// 2. 子类A的实例初始化
A的普通代码块 → A的构造方法(输出`Create A`)

注意:普通代码块在所属构造方法内的super()之后执行,但在本类构造方法剩余代码之前执行。

三、完整顺序总结(继承关系)

  1. 类加载阶段父类静态块 → 子类静态块(只执行一次,优先级最高)
  2. 对象实例化阶段父类普通代码块 → 父类构造方法子类普通代码块 → 子类构造方法 (每次new都会执行)

四、其他的

1. 为什么父类加载完子类才能加载?

  • 技术本质:子类的类结构(如方法表)依赖父类信息。
  • JVM在解析子类时,需要确保父类的字段、方法等元数据已存在,否则无法正确构建子类的内存结构。

2. 为什么父类普通代码块先于子类执行?

  • 构造方法链规则:子类构造方法必须通过super()调用父类构造方法。
  • 父类构造方法执行前,会先执行父类的普通代码块(可以理解为父类构造方法的一部分)。

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务