[原文链接]http://stackoverflow.com/questions/5801829/why-a-non-final-local-variable-cannot-be-used-inside-an-inner-class-and-inste
当我们在一个类的函数中声明了一个内部类A, A在使用外部类局部变量时,如果不讲外部类局部变量声明为final,就会碰到
Cannot refer to a non-final variable message inside an inner class defined in a different method
编译错误.
假设我们有以下代码
private String enclosingClassField;
private void updateStatus() {
final MutableClass ms = new MutableClass(1, 2);
Runnable doUpdateStatus = new Runnable() {
public void run() {
// you can use `EnclosingClass.this` because its is always final
EnclosingClass.this.enclosingClassField = "";
// shorthand for the previous line.
enclosingClassField = "";
// you cannot change `ms`, but you can change its mutable fields.
ms.x = 3;
}
}
/* do something with doUpdateStatus, like SwingUtilities.invokeLater() */
}
JAVA编译器是这样处理内部类的:
使用外部类局部变量: 编译器将内部类使用的外部类局部变量的值拷贝一份给内部类的构造函数, 所以当内部类运行时,它使用的是本地保存的值而不是外部类局部变量的值,且如果内部类是onClickListener, 当内部类运行时, 外部类局部变量的值早就不存在了.
外部类类变量:外部类的引用会被拷贝到内部类的构造函数中,内部类通过这个引用访问外部类的变量.
因此, 考虑到值的一致性. non-final的局部变量在传递给内部类后可以修改值,导致内部类保存的外部类局部变量值与外部类局部变量值不同;而外部类成员变量因为是通过引用访问的,不存在一致性问题.
另外引用别人的一段话:
内部类并不是直接调用方法传进来的参数,而是内部类将传进来的参数通过自己的构造器备份到了自己的内部,自己内部的方法调用的实际是自己的属性而不是外部类方法的参数。
这样理解就很容易得出为什么要用final了,因为两者从外表看起来是同一个东西,实际上却不是这样,如果内部类改掉了这些参数的值也不可能影响到原参数,然而这样却失去了参数的一致性,因为从编程人员的角度来看他们是同一个东西,如果编程人员在程序设计的时候在内部类中改掉参数的值,但是外部调用的时候又发现值其实没有被改掉,这就让人非常的难以理解和接受,为了避免这种尴尬的问题存在,所以编译器设计人员把内部类能够使用的参数设定为必须是final来规避这种莫名其妙错误的存在。