使用继承时,静态块和初始化块的执行顺序是什么?

我有两个班级家长和孩子

public class Parent {    
    public Parent() {
        System.out.println("Parent Constructor");
    }    
    static {
        System.out.println("Parent static block");    
    }    
    {
        System.out.println("Parent initialisation  block");
    }
}

public class Child extends Parent {    
    {
        System.out.println("Child initialisation block");
    }
    static {
        System.out.println("Child static block");
    }

    public Child() {
        System.out.println("Child Constructor");
    }    
    public static void main(String[] args) {
        new Child();    
    }
}

以上代码的输出将是

Parent static block
Child static block
Parent initialization  block
Parent Constructor
Child initialization block
Child Constructor

为什么Java以这种顺序执行代码?确定执行顺序的规则是什么?


答案 1

我是视觉学习的,所以这里有一个顺序的视觉表示,作为一个SSCCE

public class Example {

    static {
        step(1);
    }

    public static int step_2 = step(2);
    public int step_8 = step(8);

    public Example(int unused) {
        super();
        step(10);
    }

    {
        step(9);
    }

    // Just for demonstration purposes:
    public static int step(int step) {
        System.out.println("Step " + step);
        return step;
    }
}
public class ExampleSubclass extends Example {

    {
        step(11);
    }

    public static int step_3 = step(3);
    public int step_12 = step(12);

    static {
        step(4);
    }

    public ExampleSubclass(int unused) {
        super(step(7));
        step(13);
    }

    public static void main(String[] args) {
        step(5);
        new ExampleSubclass(step(6));
        step(14);
    }
}

这打印:

Step 1
Step 2
Step 3
Step 4
Step 5
Step 6
Step 7
Step 8
Step 9
Step 10
Step 11
Step 12
Step 13
Step 14

请记住,零件的顺序很重要;回头看看 的东西和 '的顺序之间的区别。staticExamplestaticExampleSubclass

另请注意,无论顺序如何,实例初始化块始终在构造函数中的调用之后立即执行(即使该调用是隐含/省略的)。但是,初始化块和字段初始值设定项之间的顺序确实很重要。super()


答案 2

有几种规则在起作用

  • 静态块始终在创建对象之前运行,因此这就是您同时看到来自父级和子级静态块的打印消息的原因
  • 现在,当您调用子类(子类)的构造函数时,此构造函数在执行其自己的构造函数之前隐式调用。初始化块甚至在构造函数调用之前就开始起作用,所以这就是为什么首先调用它的原因。因此,现在您的父类已创建,程序可以继续创建子类,这将经历相同的过程。super();

解释:

  1. 首先执行父级的静态块,因为它首先被装入,并且在装入类时调用静态块。

推荐