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

时间:2014-07-24 07:20:38

标签: 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);
    }
}

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

ini
cons
stat
ini
cons
0

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

2 个答案:

答案 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之前调用构造函数。