目录
二、Java 匿名类引用外部类成员变量为什么又不需要final修饰?
一、方法的局部变量被引用内部类为啥final修饰
void test() throws InterruptedException {
//开始执行方法
Student student = new Student();
student.setAge(1);
System.out.println(System.identityHashCode(student));
//执行内部类
new InnerInterfaceTest() {
@Override
public void print() {
System.out.println(System.identityHashCode(student));
outStr = "adsadsdas";
System.out.println("innerclass:" + student.getAge());
System.out.println("innerclass:" + outStr);
}
}.print();
//执行余下方法
}
对于上图代码,由于内部类和方法的执行的顺序不同可能会出现如下两种截
然不同的顺序,我们期望的结果是第一幅图结果。对于内部类参数的传递有两种方
式,第一种是capture-by-reference,另外一种是capture-by-value,如果是按照第一
个图的执行顺序,不管哪种传值方式都是会正确的将值专递给内部类,而且不会影响
结果。如果按照第二幅图执行顺序,可能会出现npe。
如果按照capture-by-reference:
如果采用capture-by-reference闭包方式,则a赋值给a1,a1
和a应该是同一个引用的,不会再内部类在创建一个新的引用,如果匿名内部类
执行的还未结束,但是局部已经执行结束,如第二幅图:1->2->3->4->5->6,会出一个
问题,a这个方法已经结束了,对象a已经被收回,此时对于a1会出现npe,因此
capture-by-reference在此处不适合。
如果按照capture-by-value:
采用capture-by-value内部匿名类会复制一个引用,即a1和a不是同一个引用,但
是指向的是同一块堆内存地址,不会出现npe问题,但是会出现另外一个问题:4改变a执
行的内容匿名内部类感知不到,同样6改变内容外部方法感知不到,因此为了数据一致性
考虑,对于局部方法使用匿名内部类,强制加final修饰,解决数据一致性。
总结:
局部方法传参给匿名内部类,采用的是capture-by-value,而又为了保证数据的一
致性,迫不得已采用final修饰。
二、Java 匿名类引用外部类成员变量为什么又不需要final修饰?
由于外部类的生命周期大于内部的生命周期,因此外部类的成员变量
是采用capture-by-reference,在外部成员变量销毁时,内部类引用的肯定是
早于外部类,就不会出现npe问题。