您好我正在浏览SCJP关于内部类的书,并发现了这个陈述,它就是这样的。
方法本地类只能引用标记为
的局部变量final
在解释中,指定的原因是关于本地类对象的范围和生命周期以及堆上的局部变量,但我无法理解。我在这里遗漏了final
??
答案 0 :(得分:6)
原因是,当创建方法本地类实例时,它引用的所有方法局部变量实际上都由编译器复制到其中。这就是为什么只能访问final
个变量的原因。 final
变量或引用是不可变的,因此它与方法本地对象中的副本保持同步。如果不是这样,原始值/引用可以在创建方法本地类之后更改,让位于混乱的行为和微妙的错误。
从JavaSpecialist newsletter no. 25:
中考虑这个例子public class Access1 {
public void f() {
final int i = 3;
Runnable runnable = new Runnable() {
public void run() {
System.out.println(i);
}
};
}
}
编译器将内部类转换为:
class Access1$1 implements Runnable {
Access1$1(Access1 access1) {
this$0 = access1;
}
public void run() {
System.out.println(3);
}
private final Access1 this$0;
}
由于
i
的值是final,编译器可以将其“内联”到内部类中。
答案 1 :(得分:3)
正如我所看到的,从方法本地类(例如匿名类)访问局部变量是一件危险的事情。它是由编译器允许的,但它需要很好地理解正在发生的事情。
当实例化内部类时,将复制它使用的所有对局部变量的引用,并作为隐式构造函数参数传递(检查字节码)。实际上编译器可以允许将引用设置为非final,但这会让人感到困惑,因为如果方法在实例化后改变引用,会发生什么情况并不清楚。
然而,制作参考最终并不能消除所有问题。虽然引用是不可变的,但引用后面的对象仍然是可变的。在内部类的实例化之前完成的对象的任何突变都会被内部类看到,有时这不是程序员的意图。