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

问题描述 投票:5回答:5
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
    }
}

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

什么时候定义?

java static-variables class-variables
5个回答
10
投票

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

8.3.2.3 Restrictions on the use of Fields during Initialization

成员声明只有在成员是类或接口C的实例(分别为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

因为i的变量初始值设定项使用类方法peek在其变量初始化程序初始化j之前访问变量j的值,此时它仍然具有其默认值(§4.12.5)


2
投票

我假设通过使用类,编译器将推迟查找变量,直到类完成,因此它找到y,但如果你只是像注释一样定义它尚未定义,那么它会失败


1
投票

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

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

  • 你加载Main,调用x初始化
  • 当您将x定义为等于Main.y时,编译器会看到对类的引用,因此它将结束将x定义为类y的成员Main的当前值。它对待这种情况就好像Main是一个不同的阶级。

请注意,在这种情况下,在初始化x时,暂时没有定义y。因此,x将具有0的值。


0
投票

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


0
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.