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
}
}
为什么我被允许在课堂上使用,但不能直接使用?
何时定义?
答案 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
时,我认为会发生以下情况:
Main
,x
初始化称为x
定义为等于Main.y
时,编译器会看到对类的引用,因此它将结束将x
定义为成员{{1}的当前值类y
的。它将此案视为Main
是另一个类。请注意,在这种情况下,初始化Main
时,目前尚未定义x
。因此y
的值为x
。
答案 3 :(得分:0)
你不被允许这样做,因为它毫无意义。唯一可能的解释是 y 被初始化为零,你已经有两种说法。你不需要这个。
答案 4 :(得分:0)
也许编译器创建静态变量的引用,其中默认值与堆栈中的类一起创建,然后分配提供的值。