a can only be final here. Why? How can I reassign a in onClick() method without keeping it as private member? private void f(Button b, final int a){ b.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { int b = a*5; } }); } How can I return the 5 * a when it clicked? I mean, private void f(Button b, final int a){ b.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { int b = a*5; return b; // but return type is void } }); }
当前回答
When an anonymous inner class is defined within the body of a method, all variables declared final in the scope of that method are accessible from within the inner class. For scalar values, once it has been assigned, the value of the final variable cannot change. For object values, the reference cannot change. This allows the Java compiler to "capture" the value of the variable at run-time and store a copy as a field in the inner class. Once the outer method has terminated and its stack frame has been removed, the original variable is gone but the inner class's private copy persists in the class's own memory.
(http://en.wikipedia.org/wiki/Final_%28Java%29)
其他回答
由于Jon有实现细节的答案,另一个可能的答案是JVM不想处理已经结束他的激活的写入记录。
考虑这样一个用例,在这个用例中,你的lambdas不是被应用的,而是被存储在某个地方并稍后运行。
我记得在Smalltalk中,当你做这样的修改时,你会得到一个非法的商店。
要理解这种限制的基本原理,请考虑以下程序:
public class Program {
interface Interface {
public void printInteger();
}
static Interface interfaceInstance = null;
static void initialize(int val) {
class Impl implements Interface {
@Override
public void printInteger() {
System.out.println(val);
}
}
interfaceInstance = new Impl();
}
public static void main(String[] args) {
initialize(12345);
interfaceInstance.printInteger();
}
}
The interfaceInstance remains in memory after the initialize method returns, but the parameter val does not. The JVM can’t access a local variable outside its scope, so Java makes the subsequent call to printInteger work by copying the value of val to an implicit field of the same name within interfaceInstance. The interfaceInstance is said to have captured the value of the local parameter. If the parameter weren’t final (or effectively final) its value could change, becoming out of sync with the captured value, potentially causing unintuitive behavior.
private void f(Button b, final int a[]) {
b.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
a[0] = a[0] * 5;
}
});
}
有一个技巧允许匿名类在外部作用域中更新数据。
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]);
// ...
When an anonymous inner class is defined within the body of a method, all variables declared final in the scope of that method are accessible from within the inner class. For scalar values, once it has been assigned, the value of the final variable cannot change. For object values, the reference cannot change. This allows the Java compiler to "capture" the value of the variable at run-time and store a copy as a field in the inner class. Once the outer method has terminated and its stack frame has been removed, the original variable is gone but the inner class's private copy persists in the class's own memory.
(http://en.wikipedia.org/wiki/Final_%28Java%29)
推荐文章
- Java中文件中的行数
- 指定的子节点已经有一个父节点。你必须先在子对象的父对象上调用removeView() (Android)
- 对于一个布尔字段,它的getter/setter的命名约定是什么?
- 如何获得当前屏幕方向?
- 如何在Android中渲染PDF文件
- 如何计算一个元素在列表中出现的次数
- c++中类似于java的instanceof
- 我如何解决错误“minCompileSdk(31)指定在一个依赖的AAR元数据”在本机Java或Kotlin?
- 如何POST表单数据与Spring RestTemplate?
- Mockito中检测到未完成的存根
- 我应该如何复制字符串在Java?
- “while(true)”循环有那么糟糕吗?
- 这个方法签名中的省略号(…)是干什么用的?
- Java:如何测试调用System.exit()的方法?
- 带有返回类型的Java方法在没有返回语句的情况下编译