1

我有一堆表视图,其中有重复的代码。他们过去直接继承 AbstractView 类。所以然后我让它们继承 AbstractListView(这又会从 AbstractView 继承),这将是包含这些表的所有公共属性的新类。

因为我做了那个改变,所以这个循环的行为很奇怪:

for (AbstractViewPanel view : registeredViews) {
        view.modelPropertyChange(evt);
}

这是arrayList:registeredViews:

private ArrayList<AbstractViewPanel> registeredViews;

我已经运行了调试器,并且registeredViews arrayList 具有所有视图,包括表格视图。由于某种原因,它在集合中最后一个直接继承的视图处停止并完全跳过它们。

我所有的观点过去都是直接继承的:

public class someView extends AbstractViewPanel

现在由于我的改变,一些观点是这样的:

public class someOtherView extends AbstractListView

这是抽象列表视图:

public abstract class AbstractListView extends AbstractViewPanel

这是 AbstractViewPanel

public abstract class AbstractViewPanel extends JPanel {


public abstract void modelPropertyChange(PropertyChangeEvent evt);

}

该循环根本不会遍历任何继承 AbstractListView 的东西,但我会假设最后的所有视图都是 AbstractView 类型的。

更新 我设法找到了一种解决方法,它只涉及更改循环:

for (int i = 0; i < registeredViews.size(); i++) 
{
        registeredViews.get(i).modelPropertyChange(evt);
}

我想知道为什么 foreach 样式循环让我头疼。

4

2 回答 2

1

作为参考,我创建了您设计的骨架sscceList<E>implements Iterable<E>,所以没有先验的原因你foreach应该失败。这里有几件事要检查:

  • 验证 GUI 对象事件分派线程上构建和操作。

  • ClassCastExceptionSomeOtherViewList. _

  • 由于List是异构的,请参阅Bloch,Effective Java 2nd ed。,第 29 条:考虑类型安全的异构容器。”这里提到了该模式。

  • 附录:在这种情况下你不会看到并发修改异常吗?

    不,ConcurrentModificationException“并不总是表明一个对象已被不同的线程同时修改。” 如果“列表已在结构上修改”在迭代器之外,则在尽最大努力的基础上抛出异常。更有可能的是,失败的迭代器是添加一些视图之后但添加其他视图之前获得的。如果列表是在初始线程上构建并在 EDT 上迭代的,这可能会发生意外。

SSCCE:

import java.awt.EventQueue;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Test {

    private List<AbstractViewPanel> registeredViews;

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new Test().init();
            }
        });
    }

    private void init() {
        JFrame f = new JFrame("Test");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLayout(new GridLayout(0, 1));

        registeredViews = new ArrayList<AbstractViewPanel>();
        for (int i = 0; i < 2; i++) {
            registeredViews.add(new SomeView());
            registeredViews.add(new SomeOtherView());
        }
        for (AbstractViewPanel view : registeredViews) {
            f.add(view);
        }

        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    abstract class AbstractViewPanel extends JPanel {

        public AbstractViewPanel() {
            add(new JLabel(getClass().toString()));
        }
    }

    abstract class AbstractListView extends AbstractViewPanel {
    }

    class SomeView extends AbstractViewPanel {
    }

    class SomeOtherView extends AbstractListView {
    }
}
于 2012-06-24T04:02:03.587 回答
1

我相信您modelPropertyChange会更改registeredViews列表。

因此,当您使用计数器运行循环时i,循环仅限于循环开始时列表的大小。

但是当您使用 for each 循环运行时,如果modelPropertyChange更改列表,您的迭代器可能会给您带来一些问题。

于 2012-06-24T04:06:22.687 回答