为什么Java内部类需要“最终”外部实例变量?

Why Java inner classes require “final” outer instance variables?

本问题已经有最佳答案,请猛点这里访问。
1
2
3
4
5
6
final JTextField jtfContent = new JTextField();
btnOK.addActionListener(new java.awt.event.ActionListener(){
    public void actionPerformed(java.awt.event.ActionEvent event){
        jtfContent.setText("I am OK");
    }
} );

如果我omit final湖",i a非误差问题,最终无法从内部变量jtfcontent类中定义一个不同的方法"。

为什么必须在匿名内部类的实例变量和类外类是最终要访问它?


好吧,首先,让我们放松一下,请把枪放下。

好啊。现在,语言坚持这样做的原因是它欺骗了您的内部类函数,使其能够访问所需的局部变量。运行时复制本地执行上下文(等等,视情况而定),因此它坚持您将所有东西都制作成final,这样它就可以保证事情的真实性。

如果不这样做,那么在构造对象之后但在内部类函数运行之前更改局部变量值的代码可能会令人困惑和奇怪。

这是围绕Java和"闭包"的许多喧嚣的本质。

注:开头一段是一个笑话,指的是在原作中的一些全大写的文字。


The methods in an anonymous class
don't really have access to local
variables and method parameters.
Rather, when an object of the
anonymous class is instantiated,
copies of the final local
variables and method parameters
referred to by the object's methods
are stored as instance variables in
the object. The methods in the object
of the anonymous class really access
those hidden instance variables. [1]

因此,局部类的方法访问的局部变量和方法参数必须声明为final,以防止在对象实例化后更改它们的值。

[1]http://www.developer.com/java/other/article.php/3300881/the-essential-of-oop-using-java-anonymous-classes.htm(http://www.developer.com/java/other/article.php/3300881/the-essentine-of-oop-


原因是Java不完全支持所谓的"闭包"——在这种情况下,EDCOX1的"0"不是必须的,而是通过让编译器生成一些隐藏变量来找到一个窍门,这些变量被用来给出你所看到的功能。

如果您分解生成的字节代码,您可以看到编译器是如何完成的,包括那些奇怪命名的隐藏变量,其中包含最终变量的副本。

这是一个很好的解决方案,可以在不向后弯曲语言的情况下提供功能。

编辑:对于Java 8,LAMBDAS给出了一个更简洁的方法来完成以前使用匿名类的操作。对变量的限制也从"final"放宽到"本质上是final"——您不必声明它是final,但是如果它被视为final(您可以添加final关键字,并且代码仍将编译),则可以使用它。这是一个非常好的变化。


类定义周围的变量存在于堆栈中,因此当内部类中的代码运行时(如果您想知道原因,请搜索堆栈和堆),这些变量可能会消失。这就是为什么内部类实际上不使用包含方法中的变量,而是用它们的副本构造的。

这意味着,如果在构造内部类之后更改包含方法中的变量,则其值在内部类中不会更改,即使您希望如此。为了防止混淆,Java要求它们是最终的,因此您希望不能修改它们。


因为Java 8最终修饰符对于外部实例变量是可选的。值应该是"有效的最终值"。请参阅最终和有效最终的答案差异。