Difference between <? super T> and <? extends T> in Java [duplicate]

extends

The wildcard declaration of List<? extends Number> foo3 means that any of these are legal assignments:

List<? extends Number> foo3 = new ArrayList<Number>();  // Number "extends" Number (in this context)
List<? extends Number> foo3 = new ArrayList<Integer>(); // Integer extends Number
List<? extends Number> foo3 = new ArrayList<Double>();  // Double extends Number
  1. Reading - Given the above possible assignments, what type of object are you guaranteed to read from List foo3:

    • You can read a Number because any of the lists that could be assigned to foo3 contain a Number or a subclass of Number.
    • You can't read an Integer because foo3 could be pointing at a List<Double>.
    • You can't read a Double because foo3 could be pointing at a List<Integer>.
  2. Writing - Given the above possible assignments, what type of object could you add to List foo3 that would be legal for all the above possible ArrayList assignments:

    • You can't add an Integer because foo3 could be pointing at a List<Double>.
    • You can't add a Double because foo3 could be pointing at a List<Integer>.
    • You can't add a Number because foo3 could be pointing at a List<Integer>.

You can't add any object to List<? extends T> because you can't guarantee what kind of List it is really pointing to, so you can't guarantee that the object is allowed in that List. The only "guarantee" is that you can only read from it and you'll get a T or subclass of T.

super

Now consider List <? super T>.

The wildcard declaration of List<? super Integer> foo3 means that any of these are legal assignments:

List<? super Integer> foo3 = new ArrayList<Integer>();  // Integer is a "superclass" of Integer (in this context)
List<? super Integer> foo3 = new ArrayList<Number>();   // Number is a superclass of Integer
List<? super Integer> foo3 = new ArrayList<Object>();   // Object is a superclass of Integer
  1. Reading - Given the above possible assignments, what type of object are you guaranteed to receive when you read from List foo3:

    • You aren't guaranteed an Integer because foo3 could be pointing at a List<Number> or List<Object>.
    • You aren't guaranteed a Number because foo3 could be pointing at a List<Object>.
    • The only guarantee is that you will get an instance of an Object or subclass of Object (but you don't know what subclass).
  2. Writing - Given the above possible assignments, what type of object could you add to List foo3 that would be legal for all the above possible ArrayList assignments:

    • You can add an Integer because an Integer is allowed in any of above lists.
    • You can add an instance of a subclass of Integer because an instance of a subclass of Integer is allowed in any of the above lists.
    • You can't add a Double because foo3 could be pointing at an ArrayList<Integer>.
    • You can't add a Number because foo3 could be pointing at an ArrayList<Integer>.
    • You can't add an Object because foo3 could be pointing at an ArrayList<Integer>.

PECS

Remember PECS: "Producer Extends, Consumer Super".

  • "Producer Extends" - If you need a List to produce T values (you want to read Ts from the list), you need to declare it with ? extends T, e.g. List<? extends Integer>. But you cannot add to this list.

  • "Consumer Super" - If you need a List to consume T values (you want to write Ts into the list), you need to declare it with ? super T, e.g. List<? super Integer>. But there are no guarantees what type of object you may read from this list.

  • If you need to both read from and write to a list, you need to declare it exactly with no wildcards, e.g. List<Integer>.

Example

Note this example from the Java Generics FAQ. Note how the source list src (the producing list) uses extends, and the destination list dest (the consuming list) uses super:

public class Collections { 
  public static <T> void copy(List<? super T> dest, List<? extends T> src) {
      for (int i = 0; i < src.size(); i++) 
        dest.set(i, src.get(i)); 
  } 
}

Also see How can I add to List<? extends Number> data structures?


Imagine having this hierarchy

enter image description here

1. Extends

By writing

    List<? extends C2> list;

you are saying that list will be able to reference an object of type (for example) ArrayList whose generic type is one of the 7 subtypes of C2 (C2 included):

  1. C2: new ArrayList<C2>();, (an object that can store C2 or subtypes) or
  2. D1: new ArrayList<D1>();, (an object that can store D1 or subtypes) or
  3. D2: new ArrayList<D2>();, (an object that can store D2 or subtypes) or...

and so on. Seven different cases:

    1) new ArrayList<C2>(): can store C2 D1 D2 E1 E2 E3 E4
    2) new ArrayList<D1>(): can store    D1    E1 E2  
    3) new ArrayList<D2>(): can store       D2       E3 E4
    4) new ArrayList<E1>(): can store          E1             
    5) new ArrayList<E2>(): can store             E2             
    6) new ArrayList<E3>(): can store                E3             
    7) new ArrayList<E4>(): can store                   E4             

We have a set of "storable" types for each possible case: 7 (red) sets here graphically represented

enter image description here

As you can see, there is not a safe type that is common to every case:

  • you cannot list.add(new C2(){}); because it could be list = new ArrayList<D1>();
  • you cannot list.add(new D1(){}); because it could be list = new ArrayList<D2>();

and so on.

2. Super

By writing

    List<? super C2> list;

you are saying that list will be able to reference an object of type (for example) ArrayList whose generic type is one of the 7 supertypes of C2 (C2 included):

  • A1: new ArrayList<A1>();, (an object that can store A1 or subtypes) or
  • A2: new ArrayList<A2>();, (an object that can store A2 or subtypes) or
  • A3: new ArrayList<A3>();, (an object that can store A3 or subtypes) or...

and so on. Seven different cases:

    1) new ArrayList<A1>(): can store A1          B1 B2       C1 C2    D1 D2 E1 E2 E3 E4
    2) new ArrayList<A2>(): can store    A2          B2       C1 C2    D1 D2 E1 E2 E3 E4
    3) new ArrayList<A3>(): can store       A3          B3       C2 C3 D1 D2 E1 E2 E3 E4
    4) new ArrayList<A4>(): can store          A4       B3 B4    C2 C3 D1 D2 E1 E2 E3 E4
    5) new ArrayList<B2>(): can store                B2       C1 C2    D1 D2 E1 E2 E3 E4
    6) new ArrayList<B3>(): can store                   B3       C2 C3 D1 D2 E1 E2 E3 E4
    7) new ArrayList<C2>(): can store                            C2    D1 D2 E1 E2 E3 E4

We have a set of "storable" types for each possible case: 7 (red) sets here graphically represented

enter image description here

As you can see, here we have seven safe types that are common to every case: C2, D1, D2, E1, E2, E3, E4.

  • you can list.add(new C2(){}); because, regardless of the kind of List we're referencing, C2 is allowed
  • you can list.add(new D1(){}); because, regardless of the kind of List we're referencing, D1 is allowed

and so on. You probably noticed that these types correspond to the hierarchy starting from type C2.

Notes

Here the complete hierarchy if you wish to make some tests

interface A1{}
interface A2{}
interface A3{}
interface A4{}

interface B1 extends A1{}
interface B2 extends A1,A2{}
interface B3 extends A3,A4{}
interface B4 extends A4{}

interface C1 extends B2{}
interface C2 extends B2,B3{}
interface C3 extends B3{}

interface D1 extends C1,C2{}
interface D2 extends C2{}

interface E1 extends D1{}
interface E2 extends D1{}
interface E3 extends D2{}
interface E4 extends D2{}

I love the answer from @Bert F but this is the way my brain sees it.

I have an X in my hand. If I want to write my X into a List, that List needs to be either a List of X or a List of things that my X can be upcast to as I write them in i.e. any superclass of X...

List<? super   X>

If I get a List and I want to read an X out of that List, that better be a List of X or a List of things that can be upcast to X as I read them out, i.e. anything that extends X

List<? extends X>

Hope this helps.


I'd like to visualize the difference. Suppose we have:

class A { }
class B extends A { }
class C extends B { }

List<? extends T> - reading and assigning:

|-------------------------|-------------------|---------------------------------|
|         wildcard        |        get        |              assign             |
|-------------------------|-------------------|---------------------------------|
|    List<? extends C>    |    A    B    C    |                       List<C>   |
|-------------------------|-------------------|---------------------------------|
|    List<? extends B>    |    A    B         |             List<B>   List<C>   |
|-------------------------|-------------------|---------------------------------|
|    List<? extends A>    |    A              |   List<A>   List<B>   List<C>   |
|-------------------------|-------------------|---------------------------------|

List<? super T> - writing and assigning:

|-------------------------|-------------------|-------------------------------------------|
|         wildcard        |        add        |                   assign                  |
|-------------------------|-------------------|-------------------------------------------|
|     List<? super C>     |              C    |  List<Object>  List<A>  List<B>  List<C>  |
|-------------------------|-------------------|-------------------------------------------|
|     List<? super B>     |         B    C    |  List<Object>  List<A>  List<B>           |
|-------------------------|-------------------|-------------------------------------------|
|     List<? super A>     |    A    B    C    |  List<Object>  List<A>                    |
|-------------------------|-------------------|-------------------------------------------|

In all of the cases:

  • you can always get Object from a list regardless of the wildcard.
  • you can always add null to a mutable list regardless of the wildcard.

Based on Bert F's answer I would like to explain my understanding.

Lets say we have 3 classes as

public class Fruit{}

public class Melon extends Fruit{}

public class WaterMelon extends Melon{}

Here We have

List<? extends Fruit> fruitExtendedList = …

//Says that I can be a list of any object as long as this object extends Fruit.

Ok now lets try to get some value from fruitExtendedList

Fruit fruit = fruitExtendedList.get(position)

//This is valid as it can only return Fruit or its subclass.

Again lets try

Melon melon = fruitExtendedList.get(position)

//This is not valid because fruitExtendedList can be a list of Fruit only, it may not be 
//list of Melon or WaterMelon and in java we cannot assign sub class object to 
//super class object reference without explicitly casting it.

Same is the case for

WaterMelon waterMelon = fruitExtendedList.get(position)

Now lets try to set some object in fruitExtendedList

Adding fruit object

fruitExtendedList.add(new Fruit())

//This in not valid because as we know fruitExtendedList can be a list of any 
//object as long as this object extends Fruit. So what if it was the list of  
//WaterMelon or Melon you cannot add Fruit to the list of WaterMelon or Melon.

Adding Melon object

fruitExtendedList.add(new Melon())

//This would be valid if fruitExtendedList was the list of Fruit but it may 
//not be, as it can also be the list of WaterMelon object. So, we see an invalid 
//condition already.

Finally let try to add WaterMelon object

fruitExtendedList.add(new WaterMelon())

//Ok, we got it now we can finally write to fruitExtendedList as WaterMelon 
//can be added to the list of Fruit or Melon as any superclass reference can point 
//to its subclass object.

But wait what if someone decides to make a new type of Lemon lets say for arguments sake SaltyLemon as

public class SaltyLemon extends Lemon{}

Now fruitExtendedList can be list of Fruit, Melon, WaterMelon or SaltyLemon.

So, our statement

fruitExtendedList.add(new WaterMelon())

is not valid either.

Basically we can say that we cannot write anything to a fruitExtendedList.

This sums up List<? extends Fruit>

Now lets see

List<? super Melon> melonSuperList= …

//Says that I can be a list of anything as long as its object has super class of Melon.

Now lets try to get some value from melonSuperList

Fruit fruit = melonSuperList.get(position)

//This is not valid as melonSuperList can be a list of Object as in java all 
//the object extends from Object class. So, Object can be super class of Melon and 
//melonSuperList can be a list of Object type

Similarly Melon, WaterMelon or any other object cannot be read.

But note that we can read Object type instances

Object myObject = melonSuperList.get(position)

//This is valid because Object cannot have any super class and above statement 
//can return only Fruit, Melon, WaterMelon or Object they all can be referenced by
//Object type reference.

Now, lets try to set some value from melonSuperList.

Adding Object type object

melonSuperList.add(new Object())

//This is not valid as melonSuperList can be a list of Fruit or Melon.
//Note that Melon itself can be considered as super class of Melon.

Adding Fruit type object

melonSuperList.add(new Fruit())

//This is also not valid as melonSuperList can be list of Melon

Adding Melon type object

melonSuperList.add(new Melon())

//This is valid because melonSuperList can be list of Object, Fruit or Melon and in 
//this entire list we can add Melon type object.

Adding WaterMelon type object

melonSuperList.add(new WaterMelon())

//This is also valid because of same reason as adding Melon

To sum it up we can add Melon or its subclass in melonSuperList and read only Object type object.