静态最终字段的非正向引用错误

Feu*_*mel 12 java javac forward-declaration

我正在尝试编译一个javac拒绝非法前向引用错误的Java类,其中违规引用是引用字段之后的词法上.在显示相同行为时,尽可能地删除以下类:

java.util.concurrent.Callable并且许多用途Object仅用作占位符来删除不相关的代码片段.

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

使用时编译javac Test.java,javac打印以下错误消息:

Test.java:9: illegal forward reference
    static final Object bar = foo;
                              ^
Run Code Online (Sandbox Code Playgroud)

所以编译器抱怨bar声明引用的foo同时foo应该在bar声明的范围内.但是一旦删除了barin foo的声明的引用,例如通过将第5行更改return bar;return null;,则编译器接受该类.

怎么解释这个?是我的理解向前的意思后词法错误或这是一些特殊的情况下,我不知道的?

Ada*_*man 16

您对前向参考的理解是正确的.foo对第9行的引用根本不是前向引用,因为它在声明之前没有以文本形式出现(参见Java语言规范第8.3.2.3节中构成前向引用的定义).

您观察到的行为是javac bug的症状.请参阅此错误报告.问题似乎在较新版本的编译器中得到修复,例如OpenJDK 7.

它仅影响用作最终字段的初始值的前向引用.该问题似乎同样影响静态和非静态字段.

请注意,对barin 的引用call()是合法的前向引用,因为它出现在不同的类中(请参阅Java语言规范的第8.3.2.3节中示例).

另请注意,以下每个更改都会使错误消失:

进行bar非决赛:

static Object bar = foo;
Run Code Online (Sandbox Code Playgroud)

初始化bar静态或实例初始化块:

static final Object bar;

static {
  bar = foo;
}
Run Code Online (Sandbox Code Playgroud)

将初始化移动foo到初始化块也有帮助.

bar从非最终临时引用初始化为foo:

static Object tmp = foo;
static final Object bar = tmp;
Run Code Online (Sandbox Code Playgroud)

bar使用Test.foo(由Tom Anderson发现)或this.foo在非静态情况下初始化:

static final Object bar = Test.foo;
Run Code Online (Sandbox Code Playgroud)

bar使用foo内部删除和引用对象call():

static final Object foo = method(new java.util.concurrent.Callable<Object>() {
    @Override
    public Object call() throws Exception {
        return foo;
    }   
});
Run Code Online (Sandbox Code Playgroud)