首先,让我们都放松一下,请把那把枪放下.
好.现在语言坚持的原因是它为了让你的内部类函数能够访问他们渴望的局部变量而作弊.运行时会生成本地执行上下文的副本(以及适当的等等),因此它坚持要您创建所有内容final
以使其保持诚实.
如果它不这样做,那么在构造对象之后但在内部类函数运行之前更改局部变量值的代码可能会令人困惑和奇怪.
这是围绕Java和"闭包"的许多骚动的本质.
注意:开头段落是关于OP原始构成中的一些全文字幕的笑话.
首先,让我们都放松一下,请把那把枪放下.
好.现在语言坚持的原因是它为了让你的内部类函数能够访问他们渴望的局部变量而作弊.运行时会生成本地执行上下文的副本(以及适当的等等),因此它坚持要您创建所有内容final
以使其保持诚实.
如果它不这样做,那么在构造对象之后但在内部类函数运行之前更改局部变量值的代码可能会令人困惑和奇怪.
这是围绕Java和"闭包"的许多骚动的本质.
注意:开头段落是关于OP原始构成中的一些全文字幕的笑话.
匿名类中的方法实际上无法访问局部变量和方法参数.相反,当实例化匿名类的对象时,对象方法引用的最终局部变量和方法参数的副本将作为实例变量存储在对象中.匿名类的对象中的方法实际上访问那些隐藏的实例变量.[1]
因此,必须将本地类的方法访问的局部变量和方法参数声明为final,以防止在实例化对象后它们的值发生更改.
[1] http://www.developer.com/java/other/article.php/3300881/The-Essence-of-OOP-using-Java-Anonymous-Classes.htm
原因是Java不完全支持所谓的"闭包" - 在这种情况下final
没有必要 - 但是通过让编译器生成一些隐藏变量来发现一个技巧,这些变量用于提供您看到的功能.
如果您反汇编生成的字节代码,您可以看到编译器如何执行它,包括包含最终变量副本的奇怪命名的隐藏变量.
这是一种优雅的解决方案,可以在不向后弯曲语言的情况下提供功能.
编辑:对于Java 8,lambdas提供了一种更简洁的方式来完成以前使用匿名类完成的操作.对变量的限制也从"最终"松散到"基本上是最终的" - 你不必将其声明为final,但如果它被视为最终(你可以添加final关键字,你的代码仍然可以编译)可以使用.这是一个非常好的变化.
类的定义周围的变量存在于堆栈中,因此当内部类中的代码运行时它们可能已经消失(如果你想知道原因,搜索堆栈和堆).这就是为什么内部类实际上不使用包含方法中的变量,而是使用它们的副本构造.
这意味着如果在构造内部类之后更改contains方法中的变量,则其值不会在内部类中更改,即使您期望它也是如此.为了防止混淆,Java要求它们是最终的,因此您希望不能修改它们.
由于Java 8 final修饰符对于外部实例变量是可选的.价值应该是"有效的最终".查看答案最终和有效最终之间的差异.