Nem*_*ara -1 java lambda final
我想不通为什么在 lambda 表达式中捕获的变量是最终的或有效的最终变量。我看了这个问题,真的没有得到答案。
这个变量捕获是什么?
当我为我的问题搜索解决方案时,我读到这些变量是最终的,因为并发问题。但是对于这种情况,我们为什么不能用reentrant lock
对象锁定 lambda 中的任务代码。
public class Lambda {
private int instance=0;
public void m(int i,String s,Integer integer,Employee employee) {
ActionListener actionListener = (event) -> {
System.out.println(i);
System.out.println(s);
System.out.println(integer);
System.out.println(employee.getI());
this.instance++;
employee.setI(4);
integer++;//error
s="fghj";//error
i++;//error
};
}
}
Run Code Online (Sandbox Code Playgroud)
在这个特定的代码中,我想知道为什么最后三个语句给出错误的原因,以及为什么我们要变异,Employee
因为它是一个局部变量。(Employee 只是一个带有 getter 和 setter 的类int i
。)
我也想知道为什么我们也可以变异this.instance
。
我感谢对我上面提到的所有事实的完整详细回答。
我读到这些变量是最终的,因为并发问题。
错误,这与并发无关,这完全是关于 lambdas(和匿名类)如何“捕获”变量值。
我想知道最后三个语句出错的原因
因为它们是捕获,所以它们必须是有效的。
您真的不需要知道为什么内部需要这样做,只需接受您需要遵守该规则的事实。
我想知道为什么我们可以变异
this.instance
因为代码不捕获 instance
,它捕获 this
,并且this
是隐式最终的。
lambda 主要是匿名类的语法糖。这不是真的,但为了这个解释的目的,这已经足够了,而且这个解释对于匿名类来说更容易理解。
首先了解一下,JVM中没有匿名类这种东西。实际上,也没有 lambda 表达式这样的东西,但那是另一回事了。
然而,由于 Java(语言)有匿名类,而 JVM 没有,编译器必须通过将匿名类转换为内部类来伪造它。(仅供参考:JVM 中也不存在内部类,因此编译器也必须伪造它。)
让我们通过例子来做到这一点。假设我们有这个代码:
// As anonymous class
int i = 0;
Runnable run = new Runnable() {
@Override
public void run() {
System.out.println(i);
}
}
// As lambda expression:
int i = 0;
Runnable run = () -> System.out.println(i);
Run Code Online (Sandbox Code Playgroud)
对于匿名类,编译器会生成这样的类:
final class Anon_1 implements Runnable {
private final int i;
Anon_1(int i) {
this.i = i;
}
@Override
public void run() {
System.out.println(i);
}
}
Run Code Online (Sandbox Code Playgroud)
然后将代码编译为:
int i = 0;
Runnable run = new Anon_1(i);
Run Code Online (Sandbox Code Playgroud)
这就是捕获的工作原理,通过复制“捕获”变量的值。
变量根本没有被捕获,而是值被捕获,因为 Java 在构造函数调用中是按值传递的。
现在你可以争辩说,没有理由i
应该有效地最终。当然,局部变量i
和字段i
现在是分开的,但它们可以单独修改。
但这是有原因的,而且这是一个很好的理由。i
已复制且独立的事实是完全隐藏的,并且是实现细节。程序员会经常忘记这一点,并认为它们是相同的,这将导致大量失败的代码,并且浪费了许多调试时间来提醒这一点。
为了代码清晰,必须as-if捕获了i
局部变量,并且匿名类里面的和外面的一样,因为Java语言是这样定义的,即使JVM做不到那。i
i
为了使它看起来像这样,局部变量必须是有效的最终变量,因此(在内部)变量根本没有被捕获这一事实对正在运行的代码没有影响。
归档时间: |
|
查看次数: |
213 次 |
最近记录: |