无法分配最终的局部变量

时间:2012-04-15 22:00:13

标签: java swing final mouselistener

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

  

无法分配最终的局部变量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);

6 个答案:

答案 0 :(得分:94)

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

所以,这是第一个例子:

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从方法局部变量转换为封闭类型的实例变量。或者,如果它还没有,则需要删除最终修饰符,因为最终变量只能分配一次。

更新:在Java 8中,引入了有效最终变量的概念(参见Java Language Specification)。但是,在这篇文章的第一个例子中,变量a被多次分配,这使它无法有效地成为最终版本。这意味着此示例仍然无法使用Java 8进行编译。(编译错误是“在封闭范围中定义的局部变量必须是最终的或有效的最终”)

答案 1 :(得分:4)

最终变量不能改变它的值(它与C / C ++中的const类似)。

你可能想让它成为一个类中的一个字段(当然没有final关键字),而不是一个函数内的局部变量。

答案 2 :(得分:4)

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

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

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

答案 3 :(得分:1)

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

   int a = 3;
   final int[] array = new int[1];
   array[0] = a;
   new Runnable() {
       @Override
       public void run() {
           array[0] += 3;
       }
   };

答案 4 :(得分:0)

在不知道seatno的声明的情况下,我建议在mouseClicked()方法中引入一个新的变量 not final,并执行与{{{{1}相同的工作1}}目前确实如此,因为变量似乎只在该方法中使用。

顺便说一下:将您的班级名称大写(seatno应为data)。看起来会更清楚。

答案 5 :(得分: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"))