为什么匿名内部类在使用时,方法参数和方法内局部变量必须加final?
参考解答
class A {
public static void main(String[] args){
int a = 10;
final int b = a;
Runnable r = new Runnable(){
public void run(){
System.out.println(b);
}
};
}
}
如上例所示,javac会在编译时生成 A.class 和 A$1.class,它俩是一个平级的关系。 而A$1.class 想直接访问A.class中方法内的局部变量理论上是不行的,因此javac做了一点手脚,它编译生成A$1.class时,会将x作为A$1.class的成员变量,这个成员变量对我们程序员而言是“不可见的”,并且它的取值在一开始就被固定了。
上述代码的伪代码是:
class A$1 implements Runnable{
int val;
public A$1(int val){
this.val = val
}
public void run() {
System.out.println(this.val);
}
}
class A {
public static void main(String[] args){
int a = 10;
final int b = a;
Runnable r = new A$1(b);
System.out.println(b); // 打印10
r.run(); // 打印10
}
}
现在假设b是不final的,编译也可以通过,那么伪代码变成:
class A$1 implements Runnable{
int val;
public A$1(int val){
this.val = val
}
public void run() {
System.out.println(this.val);
}
}
class A {
public static void main(String[] args){
int a = 10;
int b = a;
Runnable r = new A$1(b);
// 如果在这里修改b的值
b = 20;
System.out.println(b); // b的值已经改为20
r.run(); // 打印的是A$1对象内部的成员变量,结果还是刚开始的10,造成不一致
}
}
如果方法内局部变量和内部类的成员变量能够相互感知改变,这个特性实现了的话,称之为闭包(closure)
,而java偷懒没有实现,java是在语法上规定引用的局部变量必须是final的,避免上述的不一致情况发生。