Как перебрать смешанный список с помощью foreach? - PullRequest
1 голос
/ 26 февраля 2010

Мне интересно, как перебирать список со смешанным содержимым, используя foreach. Смотрите пример кода ниже.

public class GenericsForeach {

    class A {
        void methodA() {
            System.out.println(getClass().getSimpleName() + ": A");
        }
    }

    class B extends A {
        void methodB() {
            System.out.println(getClass().getSimpleName() + ": B");
        }
    }

    void test() {

        List<A> listOfA = new ArrayList<A>();
        listOfA.add(new A());

        List<B> listOfB = new ArrayList<B>();
        listOfB.add(new B());

        List<? super A> mixed = new ArrayList<A>();
        mixed.addAll(listOfA);
        mixed.addAll(listOfB);

        Iterator<? super A> it = mixed.iterator();
        while (it.hasNext()) {
            A item = (A) it.next();
            item.methodA();
        }

        // XXX: this does not work
        // for (A item : mixed) {
        // item.methodA();
        // }
    }

    public static void main(String[] args) {
        new GenericsForeach().test();
    }
}

Я создаю два списка с разными, но связанными типами контента A и B (B extends A). Я добавляю два списка в «смешанный» список, который, как я заявляю, содержит <? super A> типов. Поскольку этот смешанный список «потребляет» элементы типа A (или B), я применил правило PECS Блоха (Producer Extends, Consumer Super), чтобы определить, что мне нужно <? super A> здесь.

Пока все хорошо. Но теперь, когда я хочу перебрать этот смешанный список, я могу только сделать это с Iterator<? super A> и приведением A item = (A) it.next(). Когда я пытаюсь использовать цикл foreach (см. Закомментированный код), радости нет:

Несоответствие типов: невозможно преобразовать из захвата типа элемента # 8-of? супер GenericsForeach.A для GenericsForeach.A

Затмение даже услужливо предлагает

Изменить тип элемента 'на'? супер A '

но это приводит к катастрофе:

for (? super A item : mixed) {
    item.methodA();
}

Так что я не знаю. Затмение, похоже, не знает. Кто-нибудь еще здесь знает, возможно ли это, а если нет, то почему бы и нет?

Ответы [ 2 ]

11 голосов
/ 26 февраля 2010

Вы хотите просто List<A> для mixed. Мои рассуждения:

  • вы хотите иметь возможность добавлять элементы типа A, поэтому это не может быть List<? extends A> - включая List<B>, к которому нельзя добавить A.
  • вы хотите иметь возможность гарантировать, что элементы, которые вы выбираете , относятся к типу A, поэтому это не может быть List<? super A>, поскольку это может быть List<Object>, содержащий элементы не-A .

Итак, вы получите:

List<A> mixed = new ArrayList<A>();
mixed.addAll(listOfA);
mixed.addAll(listOfB);

for (A item : mixed) {
  item.methodA();
}
1 голос
/ 26 февраля 2010

Все здесь правы. Вы хотите использовать List<A>.

Но дженерики и назначения могут сбивать с толку, поэтому немного более подробного объяснения.

Во-первых, проблема, которую вы, возможно, обнаружили, заключается в том, что вы не можете сделать это: List<A> = new List<B>(). Компилятор не позволит вам назначить подтип для списка супертипов с использованием обобщенных типов. Это немного сбивает с толку, но предотвращает проблемы с несовпадением типов. (Более подробную информацию можно найти здесь: http://java.sun.com/docs/books/tutorial/java/generics/subtyping.html.) Правильная терминология для этого - List<? extends A> = new List<B>(). Это говорит компилятору, что ваше назначение допустимо.

В то же время, этот синтаксис может ввести вас в заблуждение, полагая, что <? extends A> означает, что все элементы в этой переменной расширяют A. Это не так - синтаксис просто способ сообщить компилятору о допустимых назначениях.

Итак, вы хотите использовать List<A> = new List<A>, а затем присвоить элементам List<A>, используя addAll(). Это допустимо, потому что метод addAll проверяет, чтобы убедиться, что каждый элемент действителен, прежде чем отправить его в коллекцию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...