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 } }); }
当前回答
访问被限制为局部final变量的原因是,如果所有的局部变量都是可访问的,那么它们首先需要被复制到一个单独的部分,在那里内部类可以访问它们,并且维护可变局部变量的多个副本可能会导致数据不一致。而final变量是不可变的,因此任何数量的拷贝都不会对数据的一致性产生任何影响。
其他回答
Java匿名类与Javascript闭包非常相似,但Java以不同的方式实现。(请看安徒生的答案)
所以为了不让Java开发人员对那些有Javascript背景的人的奇怪行为感到困惑。我想这就是为什么他们强迫我们使用final,这不是JVM的限制。
让我们看看下面的Javascript例子:
var add = (function () {
var counter = 0;
var func = function () {
console.log("counter now = " + counter);
counter += 1;
};
counter = 100; // line 1, this one need to be final in Java
return func;
})();
add(); // this will print out 100 in Javascript but 0 in Java
在Javascript中,计数器的值是100,因为从头到尾只有一个计数器变量。
但在Java中,如果没有final,它将打印出0,因为在创建内部对象时,0值被复制到内部类对象的隐藏属性中。(这里有两个整数变量,一个在局部方法中,另一个在内部类隐藏属性中)
因此,内部对象创建后的任何更改(如第1行)都不会影响内部对象。所以它会混淆两种不同的结果和行为(Java和Javascript之间)。
我相信这就是为什么,Java决定强制它是最终的,所以数据从开始到结束都是“一致的”。
匿名内部类中的方法可以在生成该类的线程终止后调用。在您的示例中,内部类将在事件分派线程上调用,而不是在创建它的线程中调用。因此,变量的作用域是不同的。所以为了保护这样的变量赋值范围问题,你必须声明它们为final。
由于Jon有实现细节的答案,另一个可能的答案是JVM不想处理已经结束他的激活的写入记录。
考虑这样一个用例,在这个用例中,你的lambdas不是被应用的,而是被存储在某个地方并稍后运行。
我记得在Smalltalk中,当你做这样的修改时,你会得到一个非法的商店。
也许这个把戏能给你启发
Boolean var= new anonymousClass(){
private String myVar; //String for example
@Overriden public Boolean method(int i){
//use myVar and i
}
public String setVar(String var){myVar=var; return this;} //Returns self instane
}.setVar("Hello").method(3);
private void f(Button b, final int a[]) {
b.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
a[0] = a[0] * 5;
}
});
}
推荐文章
- 到底是什么导致了堆栈溢出错误?
- 为什么Android工作室说“等待调试器”如果我不调试?
- Java:路径vs文件
- ExecutorService,如何等待所有任务完成
- Maven依赖Servlet 3.0 API?
- 如何在IntelliJ IDEA中添加目录到应用程序运行概要文件中的类路径?
- getter和setter是糟糕的设计吗?相互矛盾的建议
- Android room persistent: AppDatabase_Impl不存在
- Java的String[]在Kotlin中等价于什么?
- Intellij IDEA上的System.out.println()快捷方式
- 使用Spring RestTemplate获取JSON对象列表
- Spring JPA选择特定的列
- URLEncoder不能翻译空格字符
- Java中的super()
- 如何转换JSON字符串映射<字符串,字符串>与杰克逊JSON