在Java中使用static关键字创建对象

class abc { int a = 0; static int b; static abc h = new abc(); //line 4 public abc() { System.out.println("cons"); } { System.out.println("ini"); } static { System.out.println("stat"); } } public class ques { public static void main(String[] args) { System.out.println(new abc().a); } } 

当我写这段代码时,我按顺序得到输出:

 ini cons stat ini cons 0 

这里当我在main(), class abc创建一个新对象时main(), class abc被加载, static变量和块按照它们被写入的顺序执行。 当控制来到第4行static abc h = new abc(); 调用实例初始化块。 为什么? 为什么在第4行创建新对象时不调用静态块,直到那时静态块也没有被调用一次,所以根据惯例静态块应该被调用。 为什么会出现这种意外的输出?

静态字段初始化和静态块按它们声明的顺序执行。 在您的情况下,代码在分离声明和初始化后等效于此:

 class abc{ int a; static int b; static abc h;//line 4 static { h = new abc();//line 4 (split) System.out.println("stat"); } public abc() { a = 0; System.out.println("ini"); System.out.println("cons"); } } public class ques{ public static void main(String[] args) { System.out.println(new abc().a); } } 

因此,当您从代码到达第4行时,静态初始化实际上正在执行而尚未完成。 因此,在可以打印stat之前调用构造函数。

JLS 说 :

静态初始值设定项和类变量初始值设定项以文本顺序执行,并且可能不引用在声明在使用后以文本方式出现的类中声明的类变量,即使这些类变量在范围内(第8.3.2.3节)。 此限制旨在在编译时检测大多数循环或其他格式错误的初始化。

这正是你的情况。

以下是您的原始示例: http : //ideone.com/pIevbX – abc静态初始化程序在指定了abc静态实例之后 – 因此静态初始化程序无法执行 – 它是在静态变量初始化之后的文本

让我们静态初始化块之后移动第4行 – http://ideone.com/Em7nC1

 class abc{ int a = 0; static int b; public abc() { System.out.println("cons"); } { System.out.println("ini"); } static { System.out.println("stat"); } static abc h = new abc();//former line 4 } 

现在您可以看到以下输出:

 stat ini cons ini cons 0 

现在初始化顺序更像你期望的 – 首先调用静态初始化程序,然后以常见方式初始化abc静态实例。