管理对类变量的前向引用的精确规则在 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;
}
而下面的示例编译没有错误:
class Test {
Test() { k = 2; }
int j = 1;
int i = j;
int k;
}
即使 Test 的构造函数
(第 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 节)。