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
中创建了一个新对象时,加载了static
变量和块,按顺序执行它们。当控制进入第4行static abc h = new abc();
时,将调用实例初始化块。为什么?为什么在第4行创建新对象时不调用静态块,直到那时静态块也没有被调用一次,所以根据惯例,应该调用静态块。为什么会出现意外输出?
答案 0 :(得分:7)
JLS says:
执行静态初始值设定项和类变量初始值设定项 在文本顺序中,可能不会引用在...中声明的类变量 尽管如此,其声明在使用后以文本形式出现的类 这些类变量在范围内(§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
的静态实例。
答案 1 :(得分: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);
}
}
因此,当您从代码到达第4行时,静态初始化实际上正在执行而尚未完成。因此,在可以打印stat
之前调用构造函数。