[Covariance and contravariance]
Lets take a look at example
public class A { }
//B is A
public class B extends A { }
//C is A
public class C extends A { }
Generics allows you to work with Types dynamically in a safe way
//ListA
List<A> listA = new ArrayList<A>();
//add
listA.add(new A());
listA.add(new B());
listA.add(new C());
//get
A a0 = listA.get(0);
A a1 = listA.get(1);
A a2 = listA.get(2);
//ListB
List<B> listB = new ArrayList<B>();
//add
listB.add(new B());
//get
B b0 = listB.get(0);
Since Java's Collection is a reference type as a result we have next issues:
Problem #1
//not compiled
//danger of **adding** non-B objects using listA reference
listA = listB;
*Swift's generic does not have such problem because Collection is Value type
[About] therefore a new collection is created
Problem #2
//not compiled
//danger of **getting** non-B objects using listB reference
listB = listA;
Wildcard is a reference type feature and it can not be instantiated directly
Solution #1
<? super A>
aka lower bound aka contravariance aka consumers guarantees that it is operates by A and all superclasses, that is why it is safe to add
List<? super A> listSuperA;
listSuperA = listA;
listSuperA = new ArrayList<Object>();
//add
listSuperA.add(new A());
listSuperA.add(new B());
//get
Object o0 = listSuperA.get(0);
Solution #2
<? extends A>
aka upper bound aka covariance aka producers guarantees that it is operates by A and all subclasses, that is why it is safe to get and cast
List<? extends A> listExtendsA;
listExtendsA = listA;
listExtendsA = listB;
//get
A a0 = listExtendsA.get(0);