java - 为什么在匿名类中只能访问最终变量?

标签 java event-handling anonymous-class

  1. a 在这里只能是final。为什么?如何在 onClick() 方法中重新分配 a 而不将其保留为私有(private)成员?

    private void f(Button b, final int a){
        b.addClickHandler(new ClickHandler() {
    
            @Override
            public void onClick(ClickEvent event) {
                int b = a*5;
    
            }
        });
    }
    
  2. 如何在点击时返回 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 管理 closures 的方式所致.

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

由于该值已被复制到匿名内部类的实例中,如果该变量可以被方法的其余部分修改,这看起来会很奇怪——您可能有一些代码似乎正在处理一个外部类日期变量(因为这实际上是 发生的...您将使用在不同时间拍摄的副本)。同样,如果您可以在匿名内部类中进行更改,开发人员可能希望这些更改在封闭方法的主体中可见。

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

如果您对 Java 和 C# 闭包之间更详细的比较感兴趣,我有一个 article进一步深入。我想在这个答案中专注于 Java 方面 :)

关于java - 为什么在匿名类中只能访问最终变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9116517/

相关文章:

java - 如果我在单核机器上运行应用程序,volatile 关键字是否有用?

java - 为两个或多个方法实现匿名类

java - 为什么不在 java 的匿名类中构造函数?它与 OOPs 规则相矛盾

ios - 仅将滚动事件传递给被遮挡的 View

winforms - 获取 parent 姓名

Java 反射与抽象类

java - Android 应用程序不执行按钮单击

java - 将具体对象列表转换为抽象类型

java - FXML(JavaFX)中的图像标签,如何使用css设置大小?

jQuery解绑大量事件