2013-09-27 82 views
23

我试图发现初始化发生的顺序,或者说是为什么初始化按此顺序发生的原因。由于代码:Java静态初始化命令

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 

,为什么它发生在我完全不知道这个命令。此外,如果我在m的声明中删除了static关键字,则init块和构造函数都不会触发。任何人都可以帮我解决这个问题吗?

+1

请记住,“非静态块”中的代码将被复制到每个构造函数中。只有初始化块的相对顺序很重要,只有在调用构造函数时(看似“之前”)才会调用它们。 (在静态初始化程序之前或之后,取决于您将移动的行放在哪里)。 – millimoose

+0

现在真正奇怪的是,这意味着您可以在类自身完成初始化之前初始化一个类的实例这听起来像是一个等待发生的奇怪的错误。 – millimoose

+0

@millimoose:谢谢 - 我在回答中添加了一些关于实例初始值设定项的内容。 –

回答

27

我认为你只是缺少section 12.4.2 of the JLS,其中包括:

接下来,既可以执行类变量初始化和类的静态初始化,或接口的字段初始化,在文本顺序,如虽然他们是一个块。

“在文字顺序”部分是重要的一点。

如果从静态的变量,实例变量改变m,则字段将不会被类初始化初始化 - 它只会通过例如初始化被初始化(即当一个实例构造) 。目前,这会导致堆栈溢出 - 创建一个实例都需要创建另一个实例,它需要创建另一个实例等

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

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

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

所以这就是为什么你在“主构造函数”之前看“非静态BLOCK”。

+0

@SotiriosDelimanolis:对;将明确说明。 –

+3

我爱堆栈溢出的提及:) – Cruncher