<? супер E> и <? расширяет E> для списка

Имея следующую простую структуру класса:

class A {
}

class B extends A {
}

class C extends B {
}

Я создаю ArrayList для хранения объектов ранее созданных классов:

List<? extends A> list1 = new ArrayList<A>();
List<? extends B> list2 = new ArrayList<B>();
List<? extends C> list3 = new ArrayList<C>();

List<? super A> list4 = new ArrayList<A>();
List<? super B> list5 = new ArrayList<B>();
List<? super C> list6 = new ArrayList<C>();

В каждый из этих списков я пытаюсь добавить 1 объект каждого ранее созданного класса: A, B, C. Единственная возможная комбинация:

  • добавить объект класса A, B, C в список4

  • добавление объекта класса B и C в список5

  • добавить объект класса C в список list6. Остальные попытки дают ошибки компилятора, такие как:

Метод add (capture # 1-of? extends A) в списке типов не применяется для аргументы (A)

Почему я не могу добавить объект класса A, B, C в список1/2/3? Почему, например, list4 принимает объекты классов A, B, C, если они должны быть суперкласс класса A, поскольку список4 определен?

Ответ 1

"? extends A" означает "некоторый тип, полученный из A (или самого A)". Так, например, List<ByteArrayOutputStream> совместим с List<? extends OutputStream> - но вы не сможете добавить FileOutputStream в такой список - это означает List<ByteArrayOutputStream>! Все, что вы знаете, это то, что вы получите из списка, будет OutputStream.

"? super A" означает "некоторый тип, который является суперклассом A (или самого A)". Так, например, List<OutputStream> совместим с List<? super ByteArrayOutputStream>. Вы можете определенно добавить ByteArrayOutputStream к такому списку, но если вы выберете элемент из списка, вы не можете действительно гарантировать ему многое.

Подробнее см. Часто задаваемые вопросы по Angelics Langer Generics.

Ответ 2

Определение типа List<? extends A> неприменимо для изменяемого списка - объяснение, данное в Java generics Java Generics Pdf

>

Метод add() принимает аргументы типа E, тип элемента коллекция.     Когда фактический параметр типа есть?, Это означает какой-то неизвестный тип. Любой параметр     мы переходим к добавлению, должны быть подтипом этого неизвестного типа. С тех пор, как мы не знаю     какой тип есть, мы ничего не можем передать.

Однако, когда typedef List<? super A>, тогда параметр type? неявно напечатан.

Ответ 3

List<? extends A> list1 

Это список, элементом типа которого может быть любой неизвестный подкласс A. Например, это может быть подкласс D. Поэтому вы ничего не можете добавить к этому, это может быть неправильно...

List<? super A> list4

Это список, элемент типа которого может быть A или суперкласс A (в этом случае не существует, кроме Object). Таким образом, вы можете добавить к нему объекты A или любой подкласс A, такой как B или C.

Ответ 4

Это не работает.

Вы должны использовать <? extends T> при создании функции, аргументом которой является коллекция неизвестного подтипа некоторого типа, и вы хотите получить объекты из этой коллекции:

int sum(Collection<? extends Integer> collection) {
    for (Integer : collection) {
        // do sth
    }
    // ...
}

Вы не можете добавлять новые элементы в эту коллекцию, потому что вы не знаете, какой конкретный тип является этим холдингом коллекции. Все, что вы знаете, это то, что этот тип расширяет Integer.

Вы используете <? super T>, когда хотите добавить новые элементы типа T в коллекцию и вернуть эту коллекцию, но затем вы не можете гарантировать, что вы можете извлечь из нее, и вы должны сделать результат get() или проверить его тип. Вы можете безопасно добавлять элементы типа T и подтипы и извлекать элементы типа T.

Ответ 5

List<? super B> позволяет использовать списки любого супертипа B, т.е. list5 = новый ArrayList < A > (); или list5 = новый объект ArrayList < Object > ();

Вы можете безопасно добавить B (и подтипы) в каждый список, который использует супертипы B, но вы не можете добавить какой-либо супертип B. Представьте себе следующее:

public void myAdd(List<? super B> lst) {
  lst.add(new Object()) //this is a supertype of B (compile time error)
}
...
ArrayList<A> list = new ArrayList<A>();
myAdd(list); //tries to add Object to a list of type A