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

Lar*_*rik 5 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
    }
}
Run Code Online (Sandbox Code Playgroud)

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

什么时候定义?

Pas*_*ent 10

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

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

成员声明只有在成员是static类或接口C 的实例(分别)字段并且满足以下所有条件时才需要以文本方式显示:

  • 用法发生在C的实例(分别static)变量初始化器或C的实例(分别static)初始化器中.
  • 用法不在作业的左侧.
  • 用法是通过一个简单的名称.
  • C是封闭用法的最内层类或接口.

如果不满足上述四个要求中的任何一个,则会发生编译时错误.

这意味着测试程序会产生编译时错误:

  class Test {
      int i = j;  // compile-time error: incorrect forward reference
      int j = 1;
  }
Run Code Online (Sandbox Code Playgroud)

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

  class Test {
      Test() { k = 2; }
      int j = 1;
      int i = j;
      int k;
  }
Run Code Online (Sandbox Code Playgroud)

即使Test 的构造函数 (第8.8节)引用了后来声明为三行的字段k.

这些限制旨在在编译时捕获循环或其他格式错误的初始化.因此,两者:

class Z {
  static int i = j + 2; 
  static int j = 4;
}
Run Code Online (Sandbox Code Playgroud)

和:

class Z {
  static { i = j + 2; }
  static int i, j;
  static { j = 4; }
}
Run Code Online (Sandbox Code Playgroud)

导致编译时错误.不以这种方式检查方法的访问,因此:

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

产生输出:

0
Run Code Online (Sandbox Code Playgroud)

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