关于java:为什么我不能在不同方法中定义的内部类中引用非final变量?

why I cannot refer to a non-final variable inside an inner class defined in a different method?

本问题已经有最佳答案,请猛点这里访问。

为什么我不能引用在不同方法中定义的内部类中的非最终变量?
我看过关于这个的主题,大多数人都说您的组件应该是最终的,而且……但是没人说为什么?!!!我不知道这一限制背后的哲学是什么。
更让我困惑的是以下代码是错误的:

1
2
3
4
5
6
7
8
9
10
JButton removeJBtn = new JButton("Remove");
    JButton addJBtn = new JButton("Add");
    //...
    btnNewButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            removeJBtn.disable();//Error here,Cannot ...


        }
    });

如果我定义

1
 JButton removeJBtn

作为成员字段(在类的主体中,不是方法),不需要定义为final!


对于我(可能还有许多其他人)一直面临的每日限制,我真的很感激任何合乎逻辑的答案。

亲爱的用户,如果将此问题标记为副本,请至少参考原始问题(已确定答案!)在我的问题上面加了一个链接,我读得很透彻,但是它充满了矛盾,有些人(有88张选票)说Java捕获了最终变量的值,它完全被下面的评论(16票)否决了。


方法的局部变量位于堆栈上,并且仅存在于方法的生存期。您已经知道局部变量的作用域是仅限于变量声明的方法。当方法结束时,堆栈框架被吹走,变量是历史。但即使在方法之后完成后,在堆中创建的内部类对象可能仍然在堆中活动,如果,例如,对它的引用被传递到其他代码中,然后存储在实例变量。因为局部变量不能保证活得那么久作为方法局部内部类对象,内部类对象不能使用它们。除非局部变量被标记为final!

资料来源:Kathy Sierra SCJP


扩展其他答案,您应该记住,匿名类是语法Java糖,以防止您创建具体的类,并在每次您必须提供一个按钮侦听器时实例化它们——如果您想这样做(您可以轻松地跳过匿名类,而不用具体的类来替换它们)没有问题。您必须通过构造函数将值(这里是removeJBtn传递到对象中,以便在内部使用它们,并且您已经显式地创建了一个新对象,该对象位于堆中,因此比注册侦听器的方法长。


因为普通变量只存在于堆栈上(在您的例子中是指向对象的指针)。由于内部类可以(通常也可以)比定义方法寿命长,因此变量将不再存在。

通过使变量成为最终变量,编译器可以创建优化(在本例中:将最终变量作为"秘密"成员包含在内部类中)。如果变量不是最终变量,这将是无效的,因为它可能在之后更改。