java中的final变量只能_为什么在匿名类中只能访问final变量?

小编典典

如注释中所述,其中一些在Java 8中变得无关紧要,在Java 8中final可以隐式使用。但是,只能在匿名内部类或lambda表达式中使用有效的最终变量。

这基本上是由于Java管理闭包的方式。

创建匿名内部类的实例时,该类中使用的任何变量都将通过自动生成的构造函数复制其值。这样避免了编译器不得不自动生成各种额外的类型来保存“局部变量”的逻辑状态,例如C#编译器确实…(当C#在匿名函数中捕获变量时,它实际上捕获了变量-闭包可以通过该方法的主体看到的方式来更新变量,反之亦然。)

由于该值已被复制到匿名内部类的实例中,因此如果变量的其余部分可以被该方法的其余部分修改,则看起来会很奇怪-你可能会发现代码似乎正在使用过期的变量(因为这实际上是将要发生的事情……你将使用在不同时间拍摄的副本)。同样,如果你可以在匿名内部类中进行更改,则开发人员可能希望这些更改在封闭方法的正文中可见。

将变量设为final可以消除所有这些可能性-由于根本无法更改该值,因此你无需担心此类更改是否可见。允许方法和匿名内部类看到彼此更改的唯一方法是使用某种描述的可变类型。这可能是封闭的类本身,一个数组,一个可变的包装器类型……诸如此类。基本上,这有点像一种方法与另一种方法之间的通信:调用者看不到对一个方法的参数所做的更改,但可以看到对参数所引用的对象所做的更改。

如果你想对Java和C#闭包之间的更详细的比较感兴趣,请参阅我的文章。我想在这个答案中专注于Java方面:)

有一个技巧可以允许匿名类更新外部作用域中的数据。

private void f(Button b, final int a) {

final int[] res = new int[1];

b.addClickHandler(new ClickHandler() {

@Override

public void onClick(ClickEvent event) {

res[0] = a * 5;

}

});

// But at this point handler is most likely not executed yet!

// How should we now res[0] is ready?

}

但是,由于同步问题,此技巧不是很好。如果稍后调用处理程序,则需要1)如果从其他线程调用了处理程序,则同步对res的访问2)需要具有某种标志或指示,表明res已更新

但是,如果立即在同一线程中调用匿名类,则此技巧行得通。喜欢:

// ...

final int[] res = new int[1];

Runnable r = new Runnable() { public void run() { res[0] = 123; } };

r.run();

System.out.println(res[0]);

// ...

2020-01-10

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值