登录

去注册

登录

注册

去登录

注册

每日一问 匿名内部类访问的外部类局部变量为什么要用final 修饰,jdk8为啥不需要了? 2/3

xiaoyang   2019-08-08   收藏

  1. 匿名内部类访问的外部类局部变量为什么要用final 修饰?
  2. jdk8为啥不需要了?
6

1.因为 匿名内部类 使用的是 外部类局部变量 的值,并非引用
2.jdk8 其实用了语法糖,自动加了final,其实和原来一样

回复
3

https://jianpanwuzhe.blog.csdn.net/ 的回答做下补充

先看一下Java对匿名内部类访问外部类局部变量的处理

public class Test {
    public void fun() {
        final Data data = new Data();
        data.id = 0;
        new Test() {
            public void innerFun() {
                data.id = 1;
            }
        }.innerFun();
    }
}

上面 这段代码编译成两个class文件(一个.java文件中有几个类就会编译出几个.class文件)
匿名内部类是这样的

class Test$1 extends Test {
    final /* synthetic */ Test this$0;
    final /* synthetic */ Data val$data;

    Test$1(Test this$02, Data data) {
        this.this$0 = this$02;
        this.val$data = data;
    }

    public void innerFun() {
        this.val$data.id = 1;
    }
}

外部类是这样的


public class Test {
    public void fun() {
        Data data = new Data();
        data.id = 0;
        new Test$1(this, data).innerFun();
    }
}

可以看到,外部类以及被访问的局部变量会通过构造函数传进去,对于局部变量,内部类使用的引用和外部类使用的并不是同一个,而如果局部变量不是final的话,当其中一方对其重新赋值就会导致内部类和外部类的数据不同步,大概就是像下面这种,结果会输出false,所以要声明成final

        Data data = new Data();
        Data data1 = data;
        data = new Data();
        System.out.println(data == data1);

关于外部类的全局变量为什么不用声明为final,是因为在内部类中是通过this来访问的,这个和外部类是同一个引用

回复
0

因为内部类是通过构造参数的方式传入的外部类以及所用参数。
如果不用final会出现什么情况呢:你把变量a传给内部类了,然后对变量a重赋值了,这时候内部类和外部类的a就会出现一个是oldValue一个是newValue。
所以为了避免这个情况,就直接final规定,不让你重赋值。
为什么8不需要了呢,因为8有自动判断机制,如果你的变量没有发生重赋值,就会自动加final,类似kotlin的自动类型判断(var a=1),但是如果你违背了这种判断机制(发生了重赋值),这个时候就会报错,提示你需要内部类需要一个final修饰的变量

回复

删除留言

确认删除留言,会导致相关评论丢失?

取消 确定