除了匿名内部类内部,方法和作用域内的内部类内部使用的外部变量也必须是 final 的。
原因如下:内部类会自动拷贝外部变量的引用,为了避免:
1. 外部方法修改引用,而导致内部类得到的引用值不一致
2.内部类修改引用,而导致外部方法的参数值在修改前和修改后不一致。于是就用 final 来让该引用不可改变。
场景一:内部类访问外部类的局部变量,需要final
interface Inner {
void setW();
}
public class Outer {
public int w = 100;
public Inner getInner(final int x) {
final int y = 100;
return new Inner() {
@Override
public void setW() {
int a = x + y;
}
};
}
}
反编译后可以看到,外部类以及被访问的局部变量会通过构造函数传进去,对于局部变量,内部类使用的引用和外部类使用的并不是同一个,而如果局部变量不是final的话,当其中一方对其重新赋值就会导致内部类和外部类的数据不同步
场景二:内部类访问外部类的全局变量,不用final
interface Inner {
void setW();
}
public class Outer {
public int w = 100;
public Inner getInner() {
return new Inner() {
// 这里可以修改外部类的全局变量
public void setW() {
w = 12;
}
};
}
}
class test {
public static void main(String[] args) {
Outer outer = new Outer();
outer.getInner().setW();
System.out.println(outer.w);
}
}
运行后打印出来的w值为12,这个值在内部类Inner中改变了,但是并没有使用final也是OK的,反编译后可以看到,在内部类中是通过this来访问的,这个和外部类是同一个引用,
持有外部类的引用,这里又是全局变量,因此无需final,即可保证是同一个值
也就是说匿名内部类中持有一个外部类的引用,而自由变量 w 又是外部类的成员变量,所以完全可以通过外部类的引用来获取这个变量,然后对这个变量进行任何操作。
https://blog.csdn.net/tianjindong0804/article/details/81710268