23

我试图发现初始化发生的顺序,或者更确切地说,初始化以这种顺序发生的原因。给定代码:

public class Main {

    {
        System.out.printf("NON-STATIC BLOCK\n");
    }

    static{
        System.out.printf("STATIC BLOCK\n");
    }

    public static Main m = new Main();

    public Main(){
        System.out.printf("MAIN CONSTRUCTOR\n");
    }

    public static void main(String... args) {
        //Main m = new Main();
        System.out.printf("MAIN METHOD\n");

    }
}

输出:

STATIC BLOCK

NON-STATIC BLOCK

MAIN CONSTRUCTOR

MAIN METHOD

但是,m在初始化块之前移动的声明会产生:

NON-STATIC BLOCK

MAIN CONSTRUCTOR

STATIC BLOCK

MAIN METHOD

我完全不知道为什么它会以这种顺序发生。此外,如果我在声明中删除static关键字,m则 init 块和构造函数都不会触发。谁能帮我解决这个问题?

4

1 回答 1

28

我认为您只是缺少JLS 的第 12.4.2 节,其中包括:

接下来,按照文本顺序执行类的类变量初始化程序和静态初始化程序,或者接口的字段初始化程序,就好像它们是一个单独的块一样。

“按文本顺序”部分是重要的部分。

如果您m从静态变量更改为实例变量,则该字段将不会通过初始化进行初始化 - 它只会通过实例初始化(即构造实例时)进行初始化。目前,这将导致堆栈溢出——创建一个实例需要创建另一个实例,这需要创建另一个实例,等等。

编辑:同样第 12.5 节指定实例初始化,包括以下步骤:

  • 执行该类的实例初始化程序和实例变量初始化程序,将实例变量初始化程序的值分配给相应的实例变量,按照它们在源代码中以文本形式出现的从左到右的顺序。如果执行这些初始化程序中的任何一个导致异常,则不会处理更多初始化程序,并且此过程会突然完成相同的异常。否则,继续执行步骤 5。

  • 执行此构造函数的其余部分。如果该执行突然完成,则此过程出于同样的原因突然完成。否则,此过程正常完成。

所以这就是为什么你在“主构造器”之前看到“非静态块”。

于 2013-09-27T19:39:42.047 回答