为什么静态块无法访问其后定义的静态变量

时间:2019-03-19 06:44:26

标签: java java-8 static static-block

我已经检查了Forward References During Field Initialization和这个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
        }
    }

是由于以下事实:该值尚未初始化,因此我们只是明确禁止您使用它?还是我不知道与安全相关的东西?


已更新

这不是该问题的重复

  

为什么使用类名访问时不会发生这种情况?

这个问题是关于为什么我们要有这种设计?出于什么目的?

3 个答案:

答案 0 :(得分:3)

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

因此,当您为i变量分配值时,您只是对编译器说:“嘿,伙计,当您初始化该变量时,请将其值设置为...”。但是您不能使用它,直到它被初始化,因为它根本不存在。

更新:

如James Gosling,Bill Joy,Guy Steele和Gilad Bracha在《 Java语言规范》一书中所说:

  

这些限制旨在在编译时捕获循环或   否则格式错误的初始化。

考虑一下:

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规范不允许这样做。

答案 1 :(得分:0)

进一步阅读后,我认为Pavel在这一点上不太准确,正如@Holger在评论中指出的那样。

  

我们已经将i变量初始化了两次,这是不可能的,因为该字段是静态的。

12.4.2. Detailed Initialization Procedure指出

  

对于每个类或接口C,都有一个唯一的初始化锁LC 。从C到LC的映射由Java虚拟机实现自行决定。

我想初始化两次对于类初始化器本身是可以的,只要对调用客户端一次就可以了。

但是Pavel提供的演示仍然保持原样,因此我基本上只在这里重用它,但有不同的解释。

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

但是,当您直接在MyClass.i中使用j = MyClass.i + 5时,编译器将知道这没问题,因为8.3.3. Forward References During Field Initialization有四个条件。

  

具体来说,如果以下所有全部是编译时错误   正确:

     
      
  1. 出现在类或接口C中的类变量的声明   在使用class变量后,以文字形式显示;

  2.   
  3. 在C的任一类变量初始化器中使用的名称都是简单名称   或C的静态初始值设定项;

  4.   
  5. 用法不在作业的左侧;

  6.   
  7. C是包含用途的最里面的类或接口。

  8.   

answer中已经有详细的讨论。

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

  

这些限制旨在在编译时捕获循环或格式错误的初始化。

答案 2 :(得分:0)

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

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

    }
    int x = 0;

    public static void main(String[] args) {

    }
}