1

here is the code example

public static ArrayList<? extends A> get(){
   return null;
}

public static void main(String[] args){
   ArrayList<A> test=get();//not allowed
}

since A certainly is the super class of any ? extends A, why is the code snippet not allowed?

choxsword
  • 3,187
  • 18
  • 44

1 Answers1

3

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.

kaya3
  • 47,440
  • 4
  • 68
  • 97