【问题标题】:cannot assign value to "final" variable in java无法在java中为“final”变量赋值
【发布时间】:2012-04-16 12:27:14
【问题描述】:
 private void pushButtonActionPerformed(java.awt.event.ActionEvent evt)
{
    final int c=0;
    final JDialog d=new JDialog();
    JLabel l=new JLabel("Enter the Element :");
    JButton but1=new JButton("OK");
    JButton but2=new JButton("Cancel");
    final JTextField f=new JTextField(10);
    JPanel panel = new JPanel();
    but1.addActionListener(new ActionListener()
    {
        public void actionPerformed(ActionEvent e)
        {
            c=Integer.parseInt(f.getText());
            d.setVisible(false);
            d.dispose( );
        }
     });
but2.addActionListener(new ActionListener(){
    public void actionPerformed(ActionEvent e){
        d.setVisible(false);
        d.dispose( );
    }
});
}

我正在使用 netbeans 7.1.1。这是我的代码,我已将'c'声明为“final int”,但行“c=Integer.parseInt(f.getText());”我收到一个错误“无法为最终变量赋值”。如果我从声明中删除单词 final 并将其设置为“int c”,那么在同一行中我会收到错误“局部变量 c 无法从类中访问;需要声明为 final”。谁能告诉我为什么会这样?

【问题讨论】:

  • @MarkoTopolnik 不,这个被标记为“swing”:P

标签: java swing final


【解决方案1】:

您已经在一个函数中声明了 c,然后您在该函数中创建了一个匿名内部类。这个内部类 ActionListener 在您的函数终止之后仍然存在 - 因此它不能为 c 赋值,因为 c 是函数的本地类。

关于“final”的警告具有误导性——这只是编译器告诉您无法从匿名类访问瞬态局部变量。您不能仅通过将 c 设为 final 来解决问题,因为这将完全阻止对它的任何分配,但您可以将 c 设为 pushButtonActionPerformed 所在类的 instance member 。像这样的:

class Something
{
    int c;

    private void pushButtonActionPerformed(java.awt.event.ActionEvent evt)
    {
        JButton but1=new JButton("OK");
        but1.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                c=Integer.parseInt(f.getText());
            }
        });
    }
}

【讨论】:

  • “您不能从匿名类访问瞬态局部变量”的说法是错误的。不能分配最终变量也是错误的。如果这是真的,就不会有 final var 这样的东西,因为它是无用的。实际发生的是创建了一个 closure 来关闭 匿名类声明范围内的变量。 Java 仅具有您只能关闭最终变量的限制。这是为了维护线程安全。
  • 您的代码示例是错误的,因为您没有创建了一个闭包,所以匿名类的所有实例将共享相同的 int。
  • 除了上面的 Marko 讨厌之外,这是一个很好的解释,解决了我的问题。两个竖起大拇指
【解决方案2】:

我将跳过原因并直接解决:使用

final int[] c = {0};
...
c[0] = Integer.parseInt(f.getText());

完整故事请参考this post

【讨论】:

  • 我尝试了很多解决方案,只有这个技巧有效。我的变量在 AsyncTask 外部自定义类中。 +1
  • 原因是,虽然 c[] 数组的地址被 final 关键字强制为常量,但它的内容不是:它们是可变的。我投票赞成。
【解决方案3】:

但是“c=Integer.parseInt(f.getText());”这一行我收到一个错误“无法为最终变量赋值

没错。 final 变量的全部意义在于您只能分配给它们一次,但您尝试分配给它两次(一次在初始化中将其设置为0,一次在引用的行中)。来自the specification:

变量可以声明为final。 final 变量只能分配一次。声明一个变量 final 可以作为有用的文档,说明它的值不会改变,并且可以帮助避免编程错误。

如果分配了 final 变量,则会出现编译时错误,除非它在分配之前明确未分配(第 16 节)。

空白的final 是一个final 变量,其声明缺少初始化程序。

一旦分配了final 变量,它总是包含相同的值。如果final 变量持有对对象的引用,那么对象的状态可能会通过对对象的操作而改变,但变量将始终引用同一个对象。

(他们的重点,不是我的。)

与其尝试在方法中的变量中跟踪您存储在c 中的状态,不如在您正在创建的匿名ActionListener 实例中的数据成员中跟踪它。

【讨论】:

  • 使您尝试在 c 中跟踪的状态成为您在匿名 ActionListener 实例中跟踪的内容,而不是在周围函数中的变量中(我已经更新了答案)。跨度>
【解决方案4】:

这就是关键字final在java中存在的原因。变量是最终的,即它的值不能改变。如果您必须更改值,请不要将变量标记为最终值。

【讨论】:

  • 这并不能解决 OP 的问题,因为他正在改变本地类中的 var。
【解决方案5】:

使用 final 关键字声明的变量意味着它的值不能更改。 final 变量就像 常量

【讨论】:

  • 这不是 OP 的问题。他无法删除 final,因为他正在本地类中对其进行变异。
【解决方案6】:

final 使“变量”成为常数——你不能改变它。至于为什么在你删除final关键字后编译器会给你警告,我们需要看到整个代码......

编辑:

 but1.addActionListener(new ActionListener()
 {
     public void actionPerformed(ActionEvent e)
     {
         c=Integer.parseInt(f.getText());
         d.setVisible(false);
         d.dispose( );
     }
  });

我相信这是导致编译器发出警告的代码段。你不能在这个类中使用c...

【讨论】:

    【解决方案7】:

    只需从声明中删除 final 关键字并继续您的程序。因为final 关键字意味着值不变。

    【讨论】:

    • 没有回答这个问题——OP 表示他在删除 final 时遇到了另一个错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-11
    • 2015-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-28
    相关资源
    最近更新 更多