为什么匿名内部类使用的局部变量必须为final?
public class Demo{
public static void main(String [] args){
final int a = 1;
final Integer b = 1;
InterfaceA interfaceA = new InterfaceA(){
public int getInt(){
return a + 1;
}
public int getInteger(){
return b + 1;
}
}
System.out.println(interfaceA.getInt());
}
}
上面的例子里面,如果编译器允许a和b不是final,会有什么问题呢?
会在语义上令人费解!如下:
public class Demo{
public static void main(String [] args){
int a = 1;
Integer b = 1;
InterfaceA interfaceA = new InterfaceA(){
public int getInt(){
return a;
}
public int getInteger(){
return b;
}
}
a = 2;
System.out.println(interfaceA.getInt());
}
}
在这个例子里面,你明明在调用interfaceA.getInt()之前,已经把a的值改为了2,但interfaceA.getInt()返回的还是1.
虽然看起来匿名内部类的方法代码跟定义内部类的方法代码在同一个作用域,但实际上并非如此。编译器实际上还是以局部内部类的方式,先定义内部类,然后调用内部类构造方法,传入需要的变量(本例子中的a、b)。也就是说,内部类里面引用的外部类局部变量,实际上是通过方法参数,以值传递/地址传递的方式传递进来的新的变量。
这样就可以理解了,因为interfaceA 里面的a变量和main方法里面的a变量,看起来是一个变量,但实际上是两个作用域的变量。为了给程序员一种把这两个当成同一种变量的使用体验,而又不会在运行时出现意料不到的错误,故而在编译时要求被匿名内部类引用的变量必须为final。
简而言之,是为了让你能够将匿名内部类方法作用域与当前方法作用域当作一个作用域,而增加的一项约定。