为什么静态块不能访问其后定义的静态变量

why static block cannot access the static variable defined after it

我已经检查过 Forward References During Field Initialization and this the answer from @assylias,但我仍然没有得到 为什么 的答案。

为什么静态块可以分配在它之后声明的静态变量但不能访问它?

   class Parent {
        static {
            i = 2; // valid
            // can only assign new value to it instead of accessing it?
//            System.out.println(i); // invalid - compile-error
        }
        static int i = 0;
        static {
            i = 3; // valid
        }
    }

是不是因为这个值还没有初始化,所以我们才明确禁止你使用它?或者有什么我不知道的安全相关的东西?


已更新

这不是关于

的那个问题的重复

Why this doesn't happen when accessing with class name?

这个问题是关于我们为什么会有这样的设计?用于什么目的?

静态字段根据它们在代码中出现的顺序进行初始化。

因此,当您为 i 变量赋值时,您只需告诉编译器:"Hey, guy, when you get to initialize this variable, set its value to..."。但是在初始化之前你不能使用它,因为它根本不存在。

更新:

正如 James Gosling、Bill Joy、Guy Steele 和 Gilad Bracha 在 "The Java Language Specification" 书中所说:

These restrictions are designed to catch, at compile time, circular or otherwise malformed initializations.

考虑一下:

static {
            i = 2;
            j = i + 5; //should it be 7 or 15?
}
static int i = 10;
static int j;

j 变量应该是 7 还是 15? 如果它是 7,那么我们已经初始化了 i 变量两次,这是不可能的,因为该字段是静态的。如果是 15 那么 i = 2; 是什么意思?

此代码不明确,因此 Java 规范不允许这样做。

经过进一步阅读,我认为 Pavel 在这一点上并不像 在评论中指出的那样准确。

we have initialized i variable twice, which is not possible, since the field is static.

正如 12.4.2. Detailed Initialization Procedure 指出的那样

For each class or interface C, there is a unique initialization lock LC. The mapping from C to LC is left to the discretion of the Java Virtual Machine implementation.

我想初始化 twice 对 class 初始化器本身是可以的,只要它对调用 once客户。

但是 Pavel 提供的演示仍然坚持它的立场,所以我基本上只是在这里重复使用它,但有不同的解释。

static {
       i = 2;
       j = i + 5; 
       // no one knows whether "i" here initialized properly here
}
static int i = 10;
static int j;

但是当你直接在 j = MyClass.i + 5 中使用 MyClass.i 时,编译器会知道这样就可以了,因为 8.3.3. Forward References During Field Initialization 详细说明了四个条件。

Specifically, it is a compile-time error if all of the following are true:

  1. The declaration of a class variable in a class or interface C appears textually after a use of the class variable;

  2. The use is a simple name in either a class variable initializer of C or a static initializer of C;

  3. The use is not on the left hand side of an assignment;

  4. C is the innermost class or interface enclosing the use.

而且这个 已经有详细的讨论了。

总而言之,我认为这是为了 可预测的行为 添加这些限制。再一次,8.3.3. Forward References During Field Initialization 中指出的另一个官方目的。

These restrictions are designed to catch, at compile time, circular or otherwise malformed initializations.

同样适用于非静态成员。您可以在实例初始化块中为它们赋值,但不能在初始化之前使用它们。

class Parent {
    {
        x = 3; // works fine
        // System.out.println(x); // gives compilation error.

    }
    int x = 0;

    public static void main(String[] args) {

    }
}