关于java:变量应该是最终的内部监听器

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必须是最终的技术原因是什么?


这是因为您使用的是匿名内部类。编译器会为您创建类。它称之为您的外部类,并添加了$和数字,例如$$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对象。没问题。