我有一堆表视图,其中包含重复的代码。他们曾经直接继承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
这是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风格循环让我感到头痛。
答案 0 :(得分:1)
作为参考,我已经创建了你设计的骨架sscce。 List<E>
实施Iterable<E>
,因此foreach
失败的原因不存在先验原因。以下是一些要检查的事项:
验证event dispatch thread上是否只构建和操作GUI对象 。
当从ClassCastException
检索SomeOtherView
的实例时,确认您没有忽略List
。
由于List
是异质的,请参阅Bloch, Effective Java 2nd ed.,第29项:考虑类型安全的异构容器。“提到的模式为here。
附录:在这种情况下你不会看到并发修改例外吗?
不,ConcurrentModificationException
“并不总是表明某个对象已被不同的线程同时修改。”如果“列表在迭代器之外已经structurally modified”,则会尽最大努力抛出异常。更有可能的是,失败的迭代器是在添加一些视图之后获得的,但之前添加其他视图。如果列表是在初始线程上构建并在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 {
}
}
答案 1 :(得分:1)
我相信您的modelPropertyChange
会更改registeredViews
列表。
因此,当您使用计数器i
运行循环时,循环将限制为循环开始时列表的大小。
但是当你使用for循环运行时,如果modelPropertyChange
更改了列表,那么你的迭代器可能会给你一些问题。