使用循环创建 JFormattedTextField 时出现 ArrayIndexOutOfBoundsException

ArrayIndexOutOfBoundsException when using loop for creating 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
            }
        });
    }
}

我们不太容易分辨,但名称 globalZaehler2 听起来像是一个字段,而不是局部变量。在 for 循环中为 "index" 变量使用字段几乎 总是 一个坏主意......我不记得上次我想要状态在循环中像这样更改的对象。

这意味着在 actionPerformed 执行时,您可能已经多次执行循环,使用不同长度的字段。但是,如果您尝试使它成为一个局部变量,您会遇到一个不同的问题,因为您在匿名内部 class 中引用它 - 这意味着它需要是一个 final 局部变量...这就是真正的问题所在。

基本上,您希望 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 循环中的变量作为数组的索引,并且遍历整个数组时,请使用增强的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 方法中使用。