37

我有一个座位数组,该数组有两个字符串(选定的和空的)。单击鼠标时,我想遍历数组并找到选定的座位。当我按下按钮时,它说:

最终的局部变量 seatno 不能赋值,因为它是在封闭类型中定义的。

    JButton btnContinue = new JButton("Next");
    btnContinue.addMouseListener(new MouseAdapter() {
        public void mouseClicked(MouseEvent arg0) {

            for(int x=0;x<17;x++){
                if(anArray[x]=="selected"){

                    seatno = anArray[x];
                }
            }

            data page=new data(newfrom,newto,newtime,date2,seatno);
            page.setVisible(true);
            setVisible(false);
        }
    });
    btnContinue.setBounds(358, 227, 62, 23);
    contentPane.add(btnContinue);
4

6 回答 6

96

关键是来自封闭类型的方法局部变量实际上被复制到匿名类的实例中(这是因为激活框架问题,但我不会进一步详细说明,因为这与问题并不真正相关),这这就是为什么它们需要是最终的,因为嵌套类型实例中的变量不再相同。

所以,这是第一个例子:

void foo() {
    int a = 3;
    new Runnable() {
        @Override
        public void run() {
            a += 3;
        }
    };
}

这不会编译,因为您不能在匿名类的方法中引用非最终变量。当您在 的声明中添加 final 修饰符时a, 的值a将被复制到您定义的匿名类的创建实例中。但是,您将不能更改 的值a,因为更改对声明的方法不可见a

但是,匿名类不是静态的,也就是说,它们具有对封闭实例的引用(除非声明它们的方法是静态的),您可以使用它来修改封闭实例的变量:

int a = 3;

void foo() {
    new Runnable() {
        @Override
        public void run() {
            a += 3;
        }
    };
}

此示例确实编译,并且a每次run()调用匿名类实例的方法时它都会增加 3。(在此示例中,它从未被调用,但这只是一个示例。)

因此,总而言之,您需要将变量seatno从方法局部变量转换为封闭类型的实例变量。或者,如果还没有,您需要删除 final 修饰符,因为 final 变量只能分配一次。

更新:在 Java 8 中,引入了有效最终变量的概念(请参阅Java 语言规范)。然而,在这篇文章的第一个例子中,变量a被多次赋值,这阻止了它实际上是最终的。这意味着该示例仍然无法使用 Java 8 进行编译。(编译错误是“在封闭范围内定义的局部变量必须是最终的或有效的最终”)

于 2012-04-15T22:19:48.677 回答
4

final 变量不能改变它的值(它类似于 C/C++ 中的 const)。

您可能希望使其成为类中的字段(当然没有 final 关键字),而不是函数内的局部变量。

于 2012-04-15T22:03:02.600 回答
4

除了定义类成员变量,您还可以使用可变 int 来实现相同的目的。

void foo() {
    final MutableInt a = new MutableInt(3);
    new Runnable() {
        @Override
        public void run() {
           a.add(3);
        }
    };
}

由于 MutableInt 不是原始类型(因此通过引用传递)并且可以重新分配这个工作。

于 2013-07-11T20:41:16.620 回答
2

我最近遇到了类似的问题。在我的情况下,创建最终数组(或集合)并将我想在匿名类中更改的变量添加到这个数组更容易,如下所示。

   int a = 3;
   final int[] array = new int[1];
   array[0] = a;
   new Runnable() {
       @Override
       public void run() {
           array[0] += 3;
       }
   };
于 2017-02-26T17:00:35.917 回答
0

在不知道 的声明的情况下seatno,我建议在mouseClicked()方法中引入一个新变量,该变量不是最终的,并且与当前所做的工作相同seatno,因为该变量似乎只在该方法内部使用。

顺便说一句:大写你的类名(data应该是Data)。看起来会清晰很多。

于 2012-04-15T22:02:58.933 回答
0

确保您的变量没有final修饰符。

//final, can be set only when the object is created.
private final String seatno;

//no final modifier, the value can be set every time you "want"
private String seatno;

此外,要比较字符串,您应该使用equals

if(anArray[x].equals("selected"))
于 2012-04-15T22:04:25.037 回答