静态最终字段的非法前向引用错误 [英] Illegal forward reference error for static final fields
问题描述
我正在尝试编译一个 javac
拒绝的 Java 类,并出现一个非法前向引用错误,其中有问题的引用在词法上after引用的字段.以下类在显示相同行为的同时被尽可能地精简:
I'm trying to compile a Java class which javac
rejects with an illegal forward reference error, where the offending reference is lexically after the referenced field. The following class is stripped down as much as possible while showing the same behavior:
java.util.concurrent.Callable
和 Object
的许多用途只是用作占位符来删除不相关的代码.
java.util.concurrent.Callable
and the many uses of Object
are just used as placeholders to remove irrelevant pieces of code.
public class Test {
static final Object foo = method(new java.util.concurrent.Callable<Object>() {
@Override
public Object call() throws Exception {
return bar;
}
});
static final Object bar = foo;
static Object method(Object binder) {
return null;
}
}
使用 javac Test.java
编译时,javac 会打印以下错误消息:
When compiled using javac Test.java
, javac prints the following error message:
Test.java:9: illegal forward reference
static final Object bar = foo;
^
所以编译器抱怨 bar
的声明引用了 foo
而 foo
应该在 bar
的范围内> 的声明.但是一旦 foo
声明中的 bar
引用被删除,例如通过将第 5 行从 return bar;
更改为 return null;
,编译器接受该类.
So the compiler complains about bar
's declaration referencing foo
while foo
should be in the scope of bar
's declaration. But as soon as the reference of bar
in foo
's declaration is removed, e.g. by changing line 5 from return bar;
to return null;
, the class is accepted by the compiler.
这怎么解释?我对forward 的理解是词法上的意思 是错误的还是我不知道的一些特殊情况?
How can this be explained? Is my understanding of forward as meaning lexically after wrong or is this some special case I'm not aware of?
推荐答案
您对前向引用的理解是正确的.第 9 行对 foo
的引用根本不是前向引用,因为它在声明之前没有以文本形式出现(请参阅构成的定义)Java 语言规范的第 8.3.2.3 节中的前向引用).
Your understanding of forward reference is correct. The reference to foo
on line 9 isn't a forward reference at all since it doesn't appear textually before its declaration (see the definition of what constitutes a forward reference in section 8.3.2.3 of The Java Language Specification).
您观察到的行为是 javac 错误 的症状.请参阅此错误报告.该问题似乎已在较新版本的编译器中得到解决,例如OpenJDK 7.
The behavior you observe is a symptom of a javac bug. See this bug report. The problem appears to be fixed in newer versions of the compiler, e.g. OpenJDK 7.
它只影响用作 final 字段的初始值设定项的前向引用.该问题似乎同样影响静态和非静态字段.
It only affects forward references used as initializers to final fields. The issue appears to affect static and non-static fields equally.
请注意,call()
中对 bar
的引用是合法的前向引用,因为它出现在不同的类中(请参阅Java 语言规范的第 8.3.2.3 节).
Note that the reference to bar
in call()
is a legal forward reference since it occurs inside a different class (see examples in section 8.3.2.3 of The Java Language Specification).
另外,请注意以下每个更改都会使错误消失:
Also, note that each of the following alterations make the error disappear:
使 bar
成为非最终的:
static Object bar = foo;
在静态或实例初始化块中初始化bar
:
Initializing bar
in static or instance initializer block:
static final Object bar;
static {
bar = foo;
}
将 foo
的初始化移动到初始化块也有帮助.
Moving the initialization of foo
to an initializer block also helps.
从对 foo
的非最终临时引用初始化 bar
:
Initializing bar
from a non-final temporary reference to foo
:
static Object tmp = foo;
static final Object bar = tmp;
使用 Test.foo
(由 Tom Anderson 发现)或在非静态情况下使用 this.foo
初始化 bar
:
Initializing bar
with Test.foo
(found by Tom Anderson) or with this.foo
in non-static case:
static final Object bar = Test.foo;
移除 bar
并在 call()
中使用 foo
引用对象:
Removing bar
and referring to the object using foo
inside call()
:
static final Object foo = method(new java.util.concurrent.Callable<Object>() {
@Override
public Object call() throws Exception {
return foo;
}
});
这篇关于静态最终字段的非法前向引用错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!