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

Sha*_*wal 14 java static initialization

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

ini
cons
stat
ini
cons
0
Run Code Online (Sandbox Code Playgroud)

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

Kon*_*hov 7

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

}
Run Code Online (Sandbox Code Playgroud)

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

stat
ini
cons
ini
cons
0
Run Code Online (Sandbox Code Playgroud)

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


Did*_*r L 6

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

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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