2012-06-24 2 views
1

У меня была куча табличных представлений, в которых был дублирован код. Они использовали для прямого наследования класс AbstractView. Поэтому я заставил их наследовать AbstractListView (который в свою очередь наследовал бы от AbstractView), который был бы новым классом, содержащим все общие свойства для этих таблиц.Многоуровневое наследование и foreach Java loop

Поскольку я сделал, что изменение этого цикла ведет себя странно:

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.

UPDATE мне удалось найти обходной путь он просто включает в себя изменение цикла:

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

Я хотел бы знать, хотя, почему цикл Еогеасп стиль дает мне головную боль.

+0

Как определяется 'AbstractViewPanel'? – nhahtdh

+0

Кто? ArrayList является регулярным с Java, я не реализовал какой-либо пользовательский шаблон итератора. Я подозреваю проблему с потоками, хотя прямо сейчас, цикл не заканчивается, он никогда не доходит до конца функции. –

+0

Какой параметр типа указан в объявлении 'registerViews'. – trashgod

ответ

1

Для справки, я создал скелет sscce вашего дизайна. List<E> реализует Iterable<E>, поэтому нет a priori причина, по которой ваш foreach должен потерпеть неудачу. Вот несколько вещь, чтобы проверить:

  • Убедитесь, что объекты GUI построены и манипулировать только на event dispatch thread.

  • Убедитесь, что вы не с видом на 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 { 
    } 
} 
+0

Я рассмотрю все это, ваш ответ будет довольно полным, поэтому я его приму. Я сделаю обновление, когда найду основную причину этого. –

1

Я считаю, что ваш modelPropertyChange изменяет registeredViews список.

Поэтому, когда вы запускаете цикл, используя счетчик i, цикл ограничивается размером списка в начале цикла.

Но когда вы запускаете для каждого цикла, если modelPropertyChange измените список, возможно, ваш итератор даст вам некоторую проблему.

+0

Я думал, что сначала, но разве вы не увидели бы исключение параллельной модификации в этом случае? –

+0

Возможно, это было мое наиболее вероятное решение в этот момент, и это просто доказать: изменить содержимое цикла foreach, удалить 'view.modelPropertyChange (evt);' и написать 'System.out.println (" view: " + вид); '. Это работает, тогда мой ответ верен! – dash1e

+0

Я пробовал, и он ведет себя так, как вы упоминаете. Но моя модельPropertyChange не изменяет список зарегистрированныхViews, я смотрел на иерархию вызовов, и я только изначально добавляю к ней вещи и перебираю их. –

Смежные вопросы