在编写匿名内部类的时候就可能会出现这种情况,匿名内部类可能会使用到的变量:
-
外部类实例变量
-
方法或作用域内的局部变量
-
方法的参数
class Outer {
// string:外部类的实例变量
String string = "";
//ch:方法的参数
void outerTest(final char ch) {
// integer:方法内局部变量
final Integer integer = 1;
new Inner() {
void innerTest() {
System.out.println(string);
System.out.println(ch);
System.out.println(integer);
}
};
}
public static void main(String[] args) {
new Outer().outerTest(' ');
}
class Inner {
}
}
其中我们可以看到:方法或作用域内的局部变量和方法参数都要显示使用final关键字来修饰(在jdk1.7下)!
下面我们首先来说一下显示声明为final的原因:为了保持内部外部数据一致性
-
Java只是实现了capture-by-value形式的闭包,也就是匿名函数内部会重新拷贝一份自由变量,然后函数外部和函数内部就有两份数据。
-
要想实现内部外部数据一致性目的,只能要求两处变量不变。JDK8之前要求使用final修饰,JDK8聪明些了,可以使用effectively final的方式
内部类中是保存着一个指向外部类实例的引用,内部类访问外部类的成员变量都是通过这个引用。
-
在内部类修改了这个引用的数据,外部类再获取时拿到的数据是一致的!
那当你在匿名内部类里面尝试改变外部基本类型的变量的值的时候,或者改变外部引用变量的指向的时候,表面上看起来好像都成功了,但实际上并不会影响到外部的变量。所以,Java为了不让自己看起来那么奇怪,才加了这个final的限制。