对于这个问题,首先我们应该明确的一点是对于匿名内部类,它可能引用三种外部变量:外部类的成员变量外部方法或作用域内的局部变量外部方法的参数而第一种变量是不需要声明为final的,但后两种是需要声明为final的。那这是为什么呢?不急,我们首先来看第一个知识点。知识点一,匿名内部类同所有类一样,都是有构造函数的,只不过这个构造函数是隐式的,虽然是内部类,但是经过编译之后,JVM还是会为匿名内部类生成单独的class文件的,如下述代码所示。
编译前:
public class Outer {
String string = "";
void outerTest(final char ch){
final Integer integer = 1;
Inner inner = 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 {
}
}
编译后:
class Outer$1extends Outer.Inner
{
Outer$1(Outer paramOuter, char paramChar, Integer paramInteger)
{
super(paramOuter);
}
void innerTest()
{
System.out.println(this.this$0.string);
System.out.println(this.val$ch);
System.out.println(this.val$integer);
}
}
被匿名内部类引用的变量会被拷贝一份到内部类的环境中 但其后,在外部,该变量如果被修改,则内部外部不一致 虽然,不一致也无所谓,而且代码可能原本就想不一致 但是,Java语言(版本8之前)要求设置为final,以保持一致性 这叫做:诚实 。
以上,似乎并非有力的理由,但却就是这样设计的.
java8只是对‘事实上final’变量可以不声明final标识符而已,其实还是要求final。所以java8及以后虽然可以不声明final标识符,但是这种变量只能赋值,不能修改。
转自:https://www.zhihu.com/question/21395848