Наличие следующей простой структуры класса:
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 к list4
добавление объекта класса B и C к list5
добавление объекта класса C перечислить list6. Остальная часть попыток дает ошибки компилятора, такой нас:
Метод добавляет (capture#1-of? расширяется A) в списке типов, не применимо для аргументов (A)
Почему я не могу добавить объект класса A, B, C к list1/2/3? Почему, например, list4 принимает объекты классов A, B, C, если они, как предполагается, являются суперклассом класса A, поскольку list4 определяется?
"? extends A" means "some type derived from A (or A itself)". So for instance, a List
is compatible with List extends OutputStream>
- but you shouldn't be able to add a FileOutputStream
to such a list - it's meant to be a List
! All you know is that anything you fetch from the list will be an OutputStream
of some kind.
"? super A" means "some type which is a superclass of A (or A itself)". So for instance, a List
is compatible with List super ByteArrayOutputStream>
. You can definitely add a ByteArrayOutputStream
to such a list - but if you fetch an item from the list, you can't really guarantee much about it.
See Angelika Langer's Generics FAQ for much more information.
Определение типа Список extends A>
не может использоваться для изменяемого списка - объяснение, приведенное в Java generics Java Generics Pdf , равно
Метод add () принимает аргументы типа E, тип элемента коллекция. Когда фактический параметр типа?, Это означает какой-то неизвестный тип. Любой параметр мы передаем, чтобы добавить, должен быть подтип этого неизвестного типа. С тех пор, как мы не знаю что это за тип, мы не можем ничего передать.
Однако, когда typedef равен List super A>
тогда параметр типа? неявно типизирован.
List<? extends A> list1
It is a list, whose type element could be any unknown subclass of A. For example, it could be a D subclass. Therefore, you can't add anything to it, it could be wrong...
List<? super A> list4
It is a list, whose type element could be A, or a superclass of A (does not exist in that case, except Object). Therefore, you can add A objects to it, or any subclass of A such as B or C.
It doesn't work that way.
You should use extends T>
when you create function which argument is collection of unknown subtype of some type, and you want to fetch objects from that collection:
int sum(Collection<? extends Integer> collection) {
for (Integer : collection) {
// do sth
}
// ...
}
You cannot add new items to this collection, because you don't know which concrete type is this collection holding. All you know is that that type extends Integer
.
You use super T>
when you want to add new items of type T
to collection and return that collection, but then you cannot guarantee what you can retrieve from it and you have to cast result of get()
or check its type. You can safely add items of type T
and subtypes, and retrieve items of type T
.
Список super B>
позволяет использовать списки любого супертипа B, то есть list5 = new ArrayList < A > ();
or list5 = new ArrayList<Object>();
You can safely add B (and subtypes) to every list that use supertypes of B, but you can not add any supertype of B. Imagine this:
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