Variable should be final inside listener
Possible Duplicate:
Cannot refer to a non-final variable inside an inner class defined in a different method
Why are only final variables accessible in anonymous class?
在搜索中,谷歌在寻找这个问题的答案,但找不到任何答案。
我有以下代码:
1 2 3 4 5 6 7 8
| MyClass variable = new MyClass ();
Button b = new Button();
b. addActionListener(new ActionListener() {
public void actionPerformed (ActionEvent e ){
System. out. println("You clicked the button");
variable. doSomething();
}
}); |
编译器返回:
local variable variable is accessed from within inner class; needs to
be declared final
为什么variable必须是最终的技术原因是什么?
- stackoverflow.com/questions/3910324/…、stackoverflow.com/questions/1299837/…等。
- 谢谢你的链接。没有解释为什么编译器是这样设计的。为什么内部类不具有对outclasses的引用,并在需要时访问变量,而不是在第一次实例化时具有引用?
- @盖塔:如果变量是一个成员,你会得到一个点。但它是本地的。您不能依赖它定义的堆栈框架,而Java中没有这样的东西作为变量的引用。所以,如果你想使用它,你几乎必须复制一份。
这是因为您使用的是匿名内部类。编译器会为您创建类。它称之为您的外部类,并添加了$和数字,例如$、$2等。
类具有对自动初始化的外部类的引用,因此其实例可以使用外部类的方法和字段。
但是你的班级是匿名的。它是在方法内部定义的,并且可以使用在此匿名类之前定义的内部变量。问题是"它怎么能做到?"实际上,您不能引用"运行方法的实例"来访问其变量。答案是从匿名内部类引用的所有方法变量都被复制到匿名内部类。因此,变量必须是最终的:否则,某人可以从外部类更改其值,而这些更改在内部类中是不可见的。
这是因为内部类只在触发事件时执行代码。如果变量没有声明为final,那么在variable中引用的MyClass对象可以更改,并且如果需要MyClass对象,内部类将不知道应该引用哪个对象。
因此,它应该声明为最终的,这样引用就永远不会改变。
想象一下,如果没有最后一个关键字:
variable引用MyClass对象和hashCode(): 12345对象。创建了内部类,内部类中的variable使用hashCode(): 12345引用MyClass对象。
variable改为现在引用MyClass对象和hashCode(): abcde对象。内部类中的variable仍然引用MyClass对象和hashCode(): 12345对象。
当事件触发时,Java如何从这里运行代码?使用哪个MyClass对象?
现在使用最后一个关键字:
variable引用MyClass对象和hashCode(): 12345对象。创建了内部类,内部类中的variable使用hashCode(): 12345引用MyClass对象。
由于最后一个关键字,无法更改引用。
当事件触发时,Java总是知道要调用哪个EDCOX1 0对象。没问题。
- 所以编译器不够聪明,不知道它正在外部类的某个地方设置?
- 我认为这个答案不正确。"最终"要求适用于所有变量,而不仅仅是引用变量。
- @如果是正确的话。原语也会出现同样的问题。线程缓存变量,包括基元和引用。
- 同样的问题。如果原始变量在内部类之外被更改,那么它将不会反映在内部类中。因此,应宣布为最终决定。
- 内部类可以引用外部类,并使用该类访问适当的variable。
- 是的,盖达。这是一种确保它们始终正确引用同一对象的实践
- @getah:您访问的是局部变量,而不是成员。没有什么能保证当事件处理程序最终运行时,变量甚至会存在,除非将其设置为final。Java的闭包基本上是通过复制它们需要的变量来实现的,这不会提供从其他函数访问它们的假象,除非变量不能改变。
- @Corsika上述问题中提到的问题涉及(方法)局部变量。这个答案解决了一个完全不同的问题,并且对于嵌套类来说,类的字段必须是最终的,才可以访问它们,这一点完全没有必要。
- @乔森:这个答案解决了被问到的问题。Java的"闭包"是通过构造一个匿名类并将有用的最终局部变量复制到其中来实现的。它们工作的原因是因为变量不会在不破坏Java规则的情况下发生变化,所以不用担心保持两个副本同步。
- BTW.我是唯一一个感觉到Java用户正在打电话的人吗?似乎他们总是选择"解决方案",这意味着对他们来说工作最少,即使这是一个相对糟糕的解决方案…