可能重复:
Cannot refer to a non-final variable inside an inner class defined in a different method
为了从匿名类访问局部变量,将局部变量声明为final的规则是什么原因?
答案 0 :(得分:8)
...当一个对象的时候 匿名类被实例化, 最终局部变量的副本 和引用的方法参数 对象的方法存储为 对象中的实例变量。该 匿名对象中的方法 类真的访问那些隐藏的 实例变量。
因此,当地 变量和方法参数 通过本地方法访问 必须将类声明为final 防止他们的价值观发生变化 实例化对象后。
来自here。
答案 1 :(得分:7)
当您从匿名类访问final
变量时,编译器会将其值秘密复制到匿名类的成员变量中。例如:
Runnable foo() {
final int x = 42;
return new Runnable() {
void run() {
System.out.writeln(x);
}
};
}
变为:
// the actual name is generally illegal in normal java syntax
class internal_Runnable implements Runnable {
final int x;
internal_Runnable(int _x) { x = _x; }
void run() {
System.out.writeln(x);
}
}
void foo() {
final x = 42;
return new internal_Runnable(x);
}
如果变量不是final并且允许更改,则匿名类实例中缓存的值可能会不同步。这可以通过使用闭包来避免 - 也就是说,一个包含所有局部变量值的对象,原始函数和新的匿名类实例都可以访问。 .NET uses closures, for example.然而,这可能会导致性能损失,也许正是因为这个原因,Java语言设计者决定不支持完全关闭。
答案 2 :(得分:1)
匿名类是一个单独的类。它无法访问方法中的控制流。如果要在匿名类中重新分配变量,实际上只会重新分配匿名类的变量副本。这将非常容易出错,因此设计选择是为了使其成为错误。
如果您想解决此问题,请使用AtomicReference
。
答案 3 :(得分:0)
这是因为匿名内部对象可能会超出其上下文,如果它指的是非final
变量,那么它就会让它与不再存在的事物进行对话。