I always had a hard time with understanding wildcarded generics in Java, as in
<? extends A> or <? super A>. While More Fun with
Wildcards
is a good place for start, you come to a TL;DR point after some time. Lucky
for me, Heikki (fizzie) Kallasjoki provided me a succinct and complete code
snippet that summarizes the entire issue on freenode
##java channel.
First, let’s assume we have two classes A and B as follows.
class A {}
class B extends A {}
And here is the code snippet that summarizes the entire issue with wildcarded generics in Java.
static void f(List<? extends A> l) {
    A a = l.get(0); /* okay */
    l.add(new A()); /* not okay, l can be of type List<B> */
}
static void g(List<A> l) {
    A a = l.get(0); /* okay */
    l.add(new A()); /* okay */
}
static void h(List<? super A> l) {
    A a = l.get(0); /* not okay, l can be of type List<Object> */
    l.add(new A()); /* okay */
}
static {
    List<B> l = new ArrayList<>();
    f(l);           /* okay */
    g(l);           /* not okay, List<B> is not of type List<A> */
    h(l);           /* not okay, List<B> is not of type List<? super A> */
    List<Object> l2 = new ArrayList<>();
    f(l2);          /* not okay, List<Object> is not of type List<? extends A> */
    g(l2);          /* not okay, List<Object> is not of type List<A> */
    h(l2);          /* okay */
}
Hope that helps.