【问题标题】:why I cannot refer to a non-final variable inside an inner class defined in a different method? [duplicate]为什么我不能在以不同方法定义的内部类中引用非最终变量? [复制]
【发布时间】:2014-02-27 08:48:34
【问题描述】:

为什么我不能在以不同方法定义的内部类中引用非 final 变量?
我已经看到有关此的主题,其中大多数人说您的组件应该是 final 并且... .但是没人说为什么?!!而且我不知道这个限制背后的哲学是什么。
更让我困惑的是,下面的代码是错误的:

JButton removeJBtn = new JButton("Remove");
    JButton addJBtn = new JButton("Add");
    //...
    btnNewButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            removeJBtn.disable();//Error here,Cannot ...


        }
    });

如果我定义了

 JButton removeJBtn

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


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


尊敬的将此问题标记为重复的用户,请至少提供对原始问题的参考(已确定回答!),在我的问题上方添加了一个链接,我已通读但已完整由于矛盾,有人(88 票赞成)说 java 捕获了最终变量的值,但它被下面的评论(16 票)完全拒绝。

【问题讨论】:

标签: java inner-classes final


【解决方案1】:

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

来源:Kathy Sierra SCJP

【讨论】:

  • 那么你是说内部类(这里的 ActionListener)可能在 removeJBtn 被破坏的同时还活着吗?将其标记为 final 会使其保持活力吗?
  • 这不太对。请参阅此处接受的答案的评论线程:stackoverflow.com/questions/1299837/…。此外,这里对按值捕获的变量进行了很好的讨论:en.wikipedia.org/wiki/…
【解决方案2】:

因为普通变量仅驻留在堆栈上(在您的情况下是指向对象的指针)。由于内部类可以(并且通常确实)比定义方法的寿命更长,因此该变量将不再存在。

通过使变量最终,编译器可以创建优化(在这种情况下:包括最终变量作为内部类中的“秘密”成员。如果变量不是最终的,这将是无效的,因为它可能会改变之后。

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-20
      • 2014-12-09
      • 1970-01-01
      • 1970-01-01
      • 2012-12-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多