You've got it the wrong way round; ArrayList<A>
is assignable to ArrayList<? extends A>
, but you're trying to assign an ArrayList<? extends A>
to ArrayList<A>
.
In fact, List<? extends A>
is a supertype of List<A>
, not a subtype; using the REPL:
> List<A> list = new ArrayList<? extends A>();
Error:
unexpected type
required: class or interface without bounds
found: ? extends A
> List<? extends A> list = new ArrayList<A>();
[]
So your code is like String s = new Object();
, not like Object s = new String();
.
OK, so why isn't List<? extends A>
assignable to List<A>
? The answer is in the Liskov substitution principle. A List<A>
can do some things that a List<? extends A>
can't do, such as .add(new A())
:
> List<A> listA = new ArrayList<>();
[]
> listA.add(new A());
true
> List<? extends A> listExtendsA = new ArrayList<B>(); // B is a subclass of A
[]
> listExtendsA.add(new A());
Error:
incompatible types: A cannot be converted to capture#2 of ? extends A
This makes sense because you shouldn't be allowed to add an instance of A
to a List<B>
. On the other hand, List<A>
is assignable to List<? extends A>
, because a List<A>
can do everything that a List<? extends A>
can do.
Actually, a List<? extends A>
can't do very much; you can't even .add(new B())
, for example.