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).
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.
It only affects forward references used as initializers to final fields. The issue appears to affect static and non-static fields equally.
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:
Making bar
non-final:
static Object bar = foo;
Initializing bar
in static or instance initializer block:
static final Object bar;
static {
bar = foo;
}
Moving the initialization of foo
to an initializer block also helps.
Initializing bar
from a non-final temporary reference to foo
:
static Object tmp = foo;
static final Object bar = tmp;
Initializing bar
with Test.foo
(found by Tom Anderson) or with this.foo
in non-static case:
static final Object bar = Test.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;
}
});
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…