使用循环创建JFormattedTextField时的ArrayIndexOutOfBoundsException

时间:2015-11-05 12:08:39

标签: java indexoutofboundsexception jformattedtextfield

我想创建一些JFormattedTextFields,但始终得到ArrayIndexOutOfBoundsException,我不明白为什么。 变量globalZaehler2是51然后我将得到异常。但我的循环说它必须< field.length(即51)。那么globalZaehler2不能是51?当我使用((JFormattedTextField)field[globalZaehler2]).selectAll();

时,Eclipse会向我显示异常
for (globalZaehler2 = 0; globalZaehler2 < field.length; globalZaehler2++) {
    if (field[globalZaehler2] instanceof JFormattedTextField) {
        ((JFormattedTextField)field[globalZaehler2]).addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
((JFormattedTextField)field[globalZaehler2]).selectAll();
                // do something with the text in the field
            }
        });
    }
}

1 个答案:

答案 0 :(得分:3)

我们无法轻易说出来,但名称globalZaehler2让它听起来像是一个字段,而不是一个局部变量。使用字段作为&#34;索引&#34; for循环中的变量几乎总是一个坏主意...我不记得上一次我希望对象的状态在循环中如此改变。

这意味着在执行actionPerformed时,您可以使用不同长度的字段以其他方式执行循环。但是,如果你试图使它成为一个局部变量,你会遇到一个不同的问题,因为你在匿名内部类中引用它 - 这意味着它需要是一个最终的局部变量......这就是真正的问题。

基本上,您希望actionPerformed中的代码使用globalZaehler2 的值来进行循环的迭代 ...但它没有在执行期间执行循环的迭代......它在动作侦听器触发时执行。

可以通过在循环中声明一个局部变量来解决这个问题:

for (globalZaehler2 = 0; globalZaehler2 < field.length; globalZaehler2++) {
    // In Java 8 you wouldn't need the final part
    final int copy = globalZaehler2;
    // Use copy instead of globalZaehler2 within actionPerformed
}

但是,更好的解决方案有两个方面:

  • 如果使用for循环中的变量作为数组的索引,并且您正在遍历整个数组,请使用增强型环
  • 如果您发现自己在代码中多次使用公共子表达式,请将其提取到单个表达式

在您的情况下,这将是:

// We don't know the type of field, so it's hard to guess the
// type here. Likewise I *would* use the name field, but that's the
// name of the array... it should probably be called fields, as it's
// naturally plural...
for (Object fooField : field) {
    if (fooField instanceof JFormattedTextField) {
        // Again, don't bother with final in Java 8
        final JFormattedTextField textField = (JFormattedTextField) fooField;
        textField.addActionListener(new ActionListener()) {
            @Override public void actionPerformed(ActionEvent e) {
                textField.selectAll();
                // etc
            }
        });
    }
}

现在你自然地在循环中获得了一个新的局部变量(textField),所以它可以有效地final,并在actionPerformed方法中使用。