<? супер 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