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
    }
}

我怎么被允许使用Y槽,但不直接?

y什么时候定义?

有帮助吗?

解决方案

在本节中描述了有关类变量的前期参考的确切规则 §8.3.2.3 JLS:

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

仅当成员是一个实例时,成员的声明才需要在使用文本之前出现(分别 static)类或接口C的字段以及以下所有条件所保存:

  • 用法发生在一个实例中(分别 static)C的可变初始化器或在一个实例中(分别 static)C的初始化器。
  • 用法不在作业的左侧。
  • 用法是通过一个简单的名称。
  • 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的变量初始化程序使用类方法窥视访问j的变量J的值 (§4.12.5).

其他提示

我认为,通过使用类,编译器会推迟到该变量直到班级完成,因此找到y,但是如果您只是像评论一样定义它,则尚未定义,因此它会失败。

静态变量是按照课堂加载期间按声明的声明顺序定义的。当JVM会加载 Main 班级, x 将定义,然后 y. 。这就是为什么您不能直接使用 y 初始化时 x, ,您创建的东西称为 向前参考, ,您是指当前未定义的变量,这对编译器来说是非法的。

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

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

请注意,在这种情况下,初始化时 x, y 目前尚未定义。所以 x 将有一个价值 0.

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top