Ваше понимание прямая ссылка верно.Ссылка на foo
в строке 9 вовсе не является прямой ссылкой , так как она не появляется в текстовом виде до ее объявления (см. Определение того, что составляет прямая ссылка враздел 8.3.2.3 из Спецификация языка Java ).
Наблюдаемое вами поведение является признаком ошибки javac .См. этот отчет об ошибке .Эта проблема, похоже, исправлена в более новых версиях компилятора, например, OpenJDK 7 .
Это влияет только на прямых ссылок , используемых в качестве инициализаторов final поля.Эта проблема, по-видимому, одинаково влияет на статические и нестатические поля.
Обратите внимание, что ссылка на bar
в call()
является допустимой прямой ссылкой , поскольку она встречается внутри другого класса (см. примеры в разделе 8.3.2.3 Спецификация языка Java ).
Также обратите внимание, что каждое из следующих изменений приводит к исчезновению ошибки:
Создание 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;
Инициализация bar
с Test.foo
(найдена Томом Андерсоном) или с this.foo
в нестатический регистр:
static final Object bar = Test.foo;
Удаление bar
и обращение к объекту с использованием foo
внутри call()
:
static final Object foo = method(new java.util.concurrent.Callable<Object>() {
@Override
public Object call() throws Exception {
return foo;
}
});