a在这里只能是最终的。为什么?如何a在onClick()不将其保留为私有成员的情况下重新分配方法?
a
onClick()
private void f(Button b, final int a){ b.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { int b = a*5; } });
}
单击时如何返回5 * a?我是说,
5 * a
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 } });
正如评论中所指出的,其中一些在 Java 8 中变得无关紧要,其中final可能是隐式的。但是,只有一个 有效 的最终变量才能在匿名内部类或 lambda 表达式中使用。
final
这基本上是由于 Java 管理闭包的方式。
当您创建匿名内部类的实例时,该类中使用的任何变量都会通过自动生成的构造函数复制其 值。 这避免了编译器必须自动生成各种额外的类型来保存“局部变量”的逻辑状态,例如 C# 编译器......(当 C# 在匿名函数中捕获变量时,它确实捕获了变量 -闭包可以以方法主体看到的方式更新变量,反之亦然。)
由于该值已被复制到匿名内部类的实例中,因此如果该变量可以被该方法的其余部分修改,那看起来会很奇怪——您可能拥有似乎正在使用过期变量的代码(因为这实际上就是 会 发生的事情……您将使用在不同时间拍摄的副本)。同样,如果您可以在匿名内部类中进行更改,开发人员可能希望这些更改在封闭方法的主体中可见。
将变量设为 final 消除了所有这些可能性——因为值根本无法更改,您无需担心此类更改是否可见。允许方法和匿名内部类看到彼此更改的唯一方法是使用某种描述的可变类型。这可能是封闭类本身、一个数组、一个可变包装器类型......任何类似的东西。基本上,这有点像一种方法和另一种方法之间的通信:调用者看不到对一种方法的 参数所做的更改,但可以看到对参数 引用 的对象所做的更改。
如果您对 Java 和 C# 闭包之间的更详细比较感兴趣,我有一篇文章会进一步讨论。我想在这个答案中专注于 Java 方面:)