在声明之前如何访问静态变量?

时间:2010-09-13 09:03:38

标签: java static-variables class-variables

public class Main {

    static int x = Main.y;
//  static int x = y; //Not allowed; y is not defined
    static int y = x;
    public static void main(String[] args) {
        System.out.println(x);//prints 0
    }
}

为什么我被允许在课堂上使用,但不能直接使用?

何时定义?

5 个答案:

答案 0 :(得分:10)

关于类变量的前向引用的精确规则在JLS的§8.3.2.3部分中描述:

  

8.3.2.3初始化期间使用字段的限制

     

成员的声明需要   在使用之前以文本方式显示   仅当成员是实例时   (分别为static)类的字段   或接口C和所有的   以下条件成立:

     
      
  • 用法发生在实例(分别为static)变量中   C的初始化程序或实例   (分别为static)初始化   下进行。
  •   
  • 用法不在作业的左侧。
  •   
  • 使用方法是一个简单的名称。
  •   
  • C是封闭用法的最内层类或接口。
  •   
     

如果出现任何编译时错误   上面的四个要求不是   满足。

     

这意味着编译时错误   测试程序的结果:

  class Test {
      int i = j;  // compile-time error: incorrect forward reference
      int j = 1;
  }
     

而以下示例编译   没有错误:

  class Test {
      Test() { k = 2; }
      int j = 1;
      int i = j;
      int k;
  }
     

即使是构造函数   (§8.8)对于测试指的是   字段k被声明为三行   后面。

     

这些限制旨在   捕获,在编译时,循环或   否则初始化不正确。   因此,两者:

class Z {
  static int i = j + 2; 
  static int j = 4;
}
     

class Z {
  static { i = j + 2; }
  static int i, j;
  static { j = 4; }
}
     

导致编译时错误。   不签入方法访问   这样,所以:

class Z {
  static int peek() { return j; }
  static int i = peek();
  static int j = 1;
}
class Test {
  public static void main(String[] args) {
      System.out.println(Z.i);
  }
}
     

产生输出:

0
     

因为我的变量初始化器   使用类方法peek来访问   j之前的变量j的值   已被变量初始化   初始化程序,此时它仍然存在   有默认值(§4.12.5)

答案 1 :(得分:2)

我认为通过使用类,编译器会推迟查找变量,直到类完成,因此它找到y,但是如果你只是像注释那样定义它还没有定义,那么它会失败

答案 2 :(得分:1)

静态变量是在类加载期间按类声明的顺序定义的。当JVM加载Main类时,将定义x,然后y。这就是为什么你在初始化y时不能直接使用x,你创建了一个叫做前向引用的东西,你引用的是一个当前没有定义的变量,这是非法的编译器。

使用Main.y时,我认为会发生以下情况:

  • 您加载Mainx初始化称为
  • 当您将x定义为等于Main.y时,编译器会看到对类的引用,因此它将结束将x定义为成员{{1}的当前值类y的。它将此案视为Main是另一个类。

请注意,在这种情况下,初始化Main时,目前尚未定义x。因此y的值为x

答案 3 :(得分:0)

你不被允许这样做,因为它毫无意义。唯一可能的解释是 y 被初始化为零,你已经有两种说法。你不需要这个。

答案 4 :(得分:0)

也许编译器创建静态变量的引用,其中默认值与堆栈中的类一起创建,然后分配提供的值。