为什么在通过Java中的方法定义之前可以访问静态字段?

时间:2013-01-29 16:48:37

标签: java

我遇到了一件有趣的事情:

static {
    System.out.println(test);     // error cannot reference a field before it is defined
    System.out.println(cheat());  // OK! 
}

private static boolean cheat() {
    return test;
}

private static boolean test = true;

public static void main(String args[]) {}

第一种方法是错误的,你的编译器和IDE都会告诉你这是错误的。在第二种情况下,作弊是可以的,但它实际上默认字段testfalse。使用Sun JDK 6。

3 个答案:

答案 0 :(得分:11)

这是在JLS 8.3.2.3中定义的。特别是:

  

成员的声明需要在使用之前以文本方式显示[...]如果用法发生在C的静态初始值设定项中。

当你致电cheat()时,你会绕过那个规则。这实际上是该部分the list of the examples中的第五个例子。

请注意,cheat()将在静态初始化程序块中返回false,因为test尚未初始化。

答案 1 :(得分:3)

因为类加载按此顺序进行:

  • 加载类定义(方法,签名)
  • 为静态变量引用分配内存(对于test) - 尚未初始化
  • 执行static初始值设定项(用于变量)和static块 - 按顺序执行

因此,当您到达static块时,您已准备好方法定义,但没有准备好变量。使用cheat(),您实际上正在读取未初始化的值。

答案 2 :(得分:1)

这是类加载发生的通用步骤。

  1. 正在加载 - 将类加载到内存
  2. 验证 - 检查类e的二进制表示是否正确
  3. 准备 - 为类创建静态字段并将这些字段初始化为其标准默认值。
  4. 初始化 - 将为静态字段调用静态初始值设定项和初始值设定项
  5. 准备好之后,你的测试将是假的。然后在将静态变量赋值为true之前,你的静态块将会执行。这就是你得失的原因。

    尝试使你的静态变量最终。在这种情况下,你将成为现实。这是因为你的编译器本身将在字节码中嵌入值(因为字段是最终的)作为优化的一部分