以下代码:
class Test {
static {
System.out.println(x);
}
static int x = 6;
static double z;
}
会产生错误:Illegal forward reference.
和
class Test {
public static void main(String[] args) {
System.out.println(z);
int z = 8;
}
}
如果我们在main()内部声明之前使用变量,它会说:
Cannot find symbol.
所以,我的问题是为什么在静态块的情况下抛出:Illegal forward reference error
?
如何在静态块之后声明编译器知道变量?因为静态块是按顺序执行的,所以应该说找不到符号
答案 0 :(得分:2)
实际上,您的静态初始化程序是合法的。转让的左侧允许转发参考(JLS 8.3.3)。
static {
x = 10; //this works
}
static int x;
static {
z = y; //illegal forward reference error.
}
static int y;
static int z;
回答你问题的第二部分:为什么“非法转发参考”而不是“找不到符号”?
在不同类型的情况下无法找到符号错误:
static {
z = banana; //cannot find symbol
}
static int y;
static int z;
非法转发引用显示开发人员已声明变量。
[更新]:提出了其他问题:
如何在静态块之后声明编译器知道变量?因为静态块是按顺序执行的,所以应该说找不到符号
静态块在运行时中按顺序执行。它们不是按顺序编译的。编译器可以根据需要进行多次传递。
为什么编译器不检测局部变量的前向引用?
仅为字段声明转发引用。可以在声明之前在初始化块中访问字段。编译器尝试检测初始化错误。
例如,此代码是合法的:
static {
y = 100;
z = 200;
}
static int y;
static int z;
此代码在初始化序列中有错误:
static {
z = 2*y; //illegal forward reference
}
static int y;
static int z;
在声明之前无法访问局部变量,并且此逻辑对它们不起作用。
答案 1 :(得分:1)
对实例变量进行前向引用有时是合法的。 E.g:
class Test {
private void setXToTen() { // legal
x = 10;
}
static int x;
....
这意味着在前向引用实例变量的情况下,编译器可以找到符号。在某些情况下这样做是不合法的。但是“找不到符号”错误是不合适的 - 这会让人感到困惑。
答案 2 :(得分:1)
在将Java代码编译为字节代码(.class文件)之前,Java编译器会优化您的程序。由于静态变量是类级变量,因此它们在编译时可以全局访问。
代码优化器会从代码开头的程序中移出所有静态变量。稍后,所有静态块都会被优化,如果没有任何构造函数,则会创建默认构造函数,这会调用超类默认构造函数实例初始化程序块如果存在则进行优化等等。
因此,由于静态变量在代码编译之前被重新排列,因此不会出现任何错误,因此无法找到符号'。
以下是实际代码:
public class Test
{
static
{
x = 10;
}
static int x;
public static void main(String[] args)
{
System.out.println("Program starts..");
System.out.println("Program ends..");
}
static int y;
static
{
y = 20;
}
}
以下是优化代码:
public class Test
{
static int x,y;
static
{
x = 10;
}
static
{
y = 20;
}
public Test()
{
super();
}
public static void main(String[] args)
{
System.out.println("Program starts..");
System.out.println("Program ends..");
}
}
注意: java代码优化器使用了很多优化技术(算法),以获得更好的性能。以上优化的代码只是一个重新呈现。 当然,优化的代码不会是英语,但它将被称为人类不可读的格式。