Ссылка на последнее поле из лямбда-выражения

Недавно я обнаружил тонкую разницу между анонимным классом и лямбда-выражением:

public class FinalTest {
    final Runnable x = new Runnable() {
        @Override
        public void run() {
            System.out.println(x.hashCode());
        }
    };

    final Runnable y = () -> System.out.println(y.hashCode()); 
}

Обычно лямбды эквивалентны анонимным классам. Даже моя Eclipse IDE имеет рефакторинг для преобразования x лямбда (становится точно так же, как y) и конвертировать y в анонимный класс (это становится точно так же, как x). Однако лямбда дает мне ошибку компиляции, в то время как анонимный класс может быть отлично скомпилирован. Сообщение об ошибке выглядит так:

>javac FinalTest.java
FinalTest.java:9: error: self-reference in initializer
    final Runnable y = () -> System.out.println(y.hashCode());
                                                ^
1 error

Вопрос в том, почему такая разница?

1 ответ

Решение

Это связано с JLS #8.3.3, работающим с прямыми ссылками. В частности, если вы используете полностью определенное имя, оно компилируется (поскольку третье условие этого правила становится ложным . Использование - это простое имя в инициализаторе переменной экземпляра C или инициализаторе экземпляра C):

final Runnable y = () -> System.out.println(this.y.hashCode());

В случае анонимного класса четвертое условие (C является самым внутренним классом или интерфейсом, включающим использование) не выполняется, поскольку включающий класс является самим анонимным классом.

Другие вопросы по тегам