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


问题内容

我试图编译其中一个Java类javac与拒绝 非法向前引用 错误,其中有问题的参考是词汇 的基准场。在显示相同行为时,将尽可能精简以下类:

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;
    }
}

使用编译时javac Test.java,javac会显示以下错误消息:

Test.java:9: illegal forward reference
    static final Object bar = foo;
                              ^

因此,编译器抱怨bar的声明引用,foofoo应在bar的声明范围内。但是,一旦删除了barin
foo的声明的引用(例如,通过将第5行从更改return bar;为)return null;,编译器将接受该类。

如何解释呢?我对 前锋的 理解是错误 之后的词汇 意义 还是我不知道的某些特殊情况?


问题答案:

您对 前瞻性参考的 理解是正确的。第foo9行上的引用根本不是 前向引用
,因为它在声明之前不会在文本上出现(请参阅Java语言规范
8.3.2.3节中对构成 前向引用
的定义)。

您观察到的行为是javac 错误
的症状。请参阅此错误报告。该问题似乎已在较新版本的编译器(例如OpenJDK
7)中得到解决

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

请注意,对barin 的引用call()是合法的 正向引用,
因为它发生在不同的类内部(请参见Java语言规范
8.3.2.3节中示例)。

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

使bar非决赛:

static Object bar = foo;

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

static final Object bar;

static {
  bar = foo;
}

将初始化foo移至初始化程序块也有帮助。

bar从非最终临时参考中初始化foo

static Object tmp = foo;
static final Object bar = tmp;

barTest.foo(由Tom Anderson找到)或this.foo在非静态情况下初始化:

static final Object bar = Test.foo;

bar使用fooinside 移除并引用该对象call()

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