为什么匿名内部类调用的局部对象是final类型的

原创
2016/07/07 10:19
阅读数 205

 

1、匿名内部类调用实例变量是没有要求的。

2、匿名内部类调用局部变量则要求局部变量必选是final类型的,如果是Lambda表达式则要求局部变量是final或隐式final类型的。

3、实例变量存储在堆中,局部变量存储在栈中;堆在线程之间是共享的,栈则不是,栈是不同的线程互不干涉,所以为了线程安全性都要求使用局部变量。

4、局部变量(存储在栈上)的生命周期是跟着方法的,如果方法调用完毕,那么变量的生命也就结束,如果该方法内部使用了匿名内部类,该内部类又是开启了一个独立的线程,那么他和该方法不在同一个线程上,就会产生异步,可能方法所在的线程比匿名内部类的线程要提前死亡,这个时候方法的局部变量应该也要消亡,然而由于匿名内部类内部调用了方法的局部变量,所以这个时候就会发生错误,因为该变量已经是未定义(undefined)的了。所以,为了解决这个问题,才会硬性的规定 匿名内部类调用的局部对象必须是final类型的,final类型的变量在匿名内部类调用时其实是调用它的副本,由于原本不会发生改变,所以副本也就始终和原本保持一致,就算原本消亡,副本还是可以存在的。

5、联想到JavaScript,JS没有final关键字,而且也没有多线程,所以可以不用这么繁琐,但是有个问题要注意,因为异步将会导致变量的值是不可控的。

 

6、示例代码

public class InnerClass {

    // 实例变量

    private String arg = "object-arg";

 

    public void testArgs(){

        // 局部变量

        String arg2 = "local-arg";

        List<String> list = Arrays.asList("a","c","b");

        Collections.sort(list, new Comparator<String>() {

            @Override

            public int compare(String o1, String o2) {

                arg = "inner-arg";

                // arg2 ="inner-arg"; 编译错误

                return o1.compareTo(o2);

            }

        });

    }

}

 

展开阅读全文
打赏
0
1 收藏
分享
加载中
更多评论
打赏
0 评论
1 收藏
0
分享
返回顶部
顶部