从lambda表达式引用final字段

最近我发现匿名类和lambda表达式之间存在细微差别:

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

通常lambdas等同于匿名类。 甚至我的Eclipse IDE都有重构将x转换为lambda(它变得和y完全一样)并将y转换为匿名类(它变得和x完全一样)。 然而lambda给我一个编译错误,而匿名类可以完美编译。 错误消息如下所示:

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

所以问题是:为什么会有这样的差异?

这与处理前向引用的JLS#8.3.3有关。 特别是,如果使用完全限定名称,则编译它(因为该规则的第三个条件变为false) 在C的实例变量初始化程序或C的实例初始化程序中使用是简单名称

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

在匿名类的情况下,第四个条件( C是最内层的类或包含使用的接口 )不正确,因为封闭类本身就是匿名类。