What is a difference between <? super E> and <? extends E>?

JavaGenerics

Java Problem Overview


What is the difference between <? super E> and <? extends E>?

For instance when you take a look at class java.util.concurrent.LinkedBlockingQueue there is the following signature for the constructor:

public LinkedBlockingQueue(Collection<? extends E> c)

and for one for the method:

public int drainTo(Collection<? super E> c)

Java Solutions


Solution 1 - Java

The first (<? super E>) says that it's "some type which is an ancestor (superclass) of E"; the second (<? extends E>) says that it's "some type which is a subclass of E". (In both cases E itself is okay.)

So the constructor uses the ? extends E form so it guarantees that when it fetches values from the collection, they will all be E or some subclass (i.e. it's compatible). The drainTo method is trying to put values into the collection, so the collection has to have an element type of E or a superclass.

As an example, suppose you have a class hierarchy like this:

Parent extends Object
Child extends Parent

and a LinkedBlockingQueue<Parent>. You can construct this passing in a List<Child> which will copy all the elements safely, because every Child is a parent. You couldn't pass in a List<Object> because some elements might not be compatible with Parent.

Likewise you can drain that queue into a List<Object> because every Parent is an Object... but you couldn't drain it into a List<Child> because the List<Child> expects all its elements to be compatible with Child.

Solution 2 - Java

The reasons for this are based on how Java implements generics.

An Arrays Example

With arrays you can do this (arrays are covariant)

Integer[] myInts = {1,2,3,4};
Number[] myNumber = myInts;

But, what would happen if you try to do this?

myNumber[0] = 3.14; //attempt of heap pollution

This last line would compile just fine, but if you run this code, you could get an ArrayStoreException. Because you’re trying to put a double into an integer array (regardless of being accessed through a number reference).

This means that you can fool the compiler, but you cannot fool the runtime type system. And this is so because arrays are what we call reifiable types. This means that at runtime Java knows that this array was actually instantiated as an array of integers which simply happens to be accessed through a reference of type Number[].

So, as you can see, one thing is the actual type of the object, and another thing is the type of the reference that you use to access it, right?

The Problem with Java Generics

Now, the problem with Java generic types is that the type information is discarded by the compiler and it is not available at run time. This process is called type erasure. There are good reason for implementing generics like this in Java, but that's a long story, and it has to do, among other things, with binary compatibility with pre-existing code (see How we got the generics we have).

But the important point here is that since, at runtime there is no type information, there is no way to ensure that we are not committing heap pollution.

For instance,

List<Integer> myInts = new ArrayList<Integer>();
myInts.add(1);
myInts.add(2);

List<Number> myNums = myInts; //compiler error
myNums.add(3.14); //heap pollution

If the Java compiler does not stop you from doing this, the runtime type system cannot stop you either, because there is no way, at runtime, to determine that this list was supposed to be a list of integers only. The Java runtime would let you put whatever you want into this list, when it should only contain integers, because when it was created, it was declared as a list of integers.

As such, the designers of Java made sure that you cannot fool the compiler. If you cannot fool the compiler (as we can do with arrays) you cannot fool the runtime type system either.

As such, we say that generic types are non-reifiable.

Evidently, this would hamper polymorphism. Consider the following example:

static long sum(Number[] numbers) {
   long summation = 0;
   for(Number number : numbers) {
      summation += number.longValue();
   }
   return summation;
}

Now you could use it like this:

Integer[] myInts = {1,2,3,4,5};
Long[] myLongs = {1L, 2L, 3L, 4L, 5L};
Double[] myDoubles = {1.0, 2.0, 3.0, 4.0, 5.0};

System.out.println(sum(myInts));
System.out.println(sum(myLongs));
System.out.println(sum(myDoubles));

But if you attempt to implement the same code with generic collections, you will not succeed:

static long sum(List<Number> numbers) {
   long summation = 0;
   for(Number number : numbers) {
      summation += number.longValue();
   }
   return summation;
}

You would get compiler erros if you try to...

List<Integer> myInts = asList(1,2,3,4,5);
List<Long> myLongs = asList(1L, 2L, 3L, 4L, 5L);
List<Double> myDoubles = asList(1.0, 2.0, 3.0, 4.0, 5.0);

System.out.println(sum(myInts)); //compiler error
System.out.println(sum(myLongs)); //compiler error
System.out.println(sum(myDoubles)); //compiler error

The solution is to learn to use two powerful features of Java generics known as covariance and contravariance.

Covariance

With covariance you can read items from a structure, but you cannot write anything into it. All these are valid declarations.

List<? extends Number> myNums = new ArrayList<Integer>();
List<? extends Number> myNums = new ArrayList<Float>();
List<? extends Number> myNums = new ArrayList<Double>();

And you can read from myNums:

Number n = myNums.get(0); 

Because you can be sure that whatever the actual list contains, it can be upcasted to a Number (after all anything that extends Number is a Number, right?)

However, you are not allowed to put anything into a covariant structure.

myNumst.add(45L); //compiler error

This would not be allowed, because Java cannot guarantee what is the actual type of the object in the generic structure. It can be anything that extends Number, but the compiler cannot be sure. So you can read, but not write.

Contravariance

With contravariance you can do the opposite. You can put things into a generic structure, but you cannot read out from it.

List<Object> myObjs = new List<Object>();
myObjs.add("Luke");
myObjs.add("Obi-wan");

List<? super Number> myNums = myObjs;
myNums.add(10);
myNums.add(3.14);

In this case, the actual nature of the object is a List of Objects, and through contravariance, you can put Numbers into it, basically because all numbers have Object as their common ancestor. As such, all Numbers are objects, and therefore this is valid.

However, you cannot safely read anything from this contravariant structure assuming that you will get a number.

Number myNum = myNums.get(0); //compiler-error

As you can see, if the compiler allowed you to write this line, you would get a ClassCastException at runtime.

Get/Put Principle

As such, use covariance when you only intend to take generic values out of a structure, use contravariance when you only intend to put generic values into a structure and use the exact generic type when you intend to do both.

The best example I have is the following that copies any kind of numbers from one list into another list. It only gets items from the source, and it only puts items in the target.

public static void copy(List<? extends Number> source, List<? super Number> target) {
    for(Number number : source) {
        target.add(number);
    }
}

Thanks to the powers of covariance and contravariance this works for a case like this:

List<Integer> myInts = asList(1,2,3,4);
List<Double> myDoubles = asList(3.14, 6.28);
List<Object> myObjs = new ArrayList<Object>();

copy(myInts, myObjs);
copy(myDoubles, myObjs);

Solution 3 - Java

<? extends E> defines E as the upper bound: "This can be cast to E".

<? super E> defines E as the lower bound: "E can be cast to this."

Solution 4 - Java

<? super E> means any object including E that is parent of E

<? extends E> means any object including E that is child of E .

Solution 5 - Java

I'm going to try and answer this. But to get a really good answer you should check Joshua Bloch's book Effective Java (2nd Edition). He describes the mnemonic PECS, which stands for "Producer Extends, Consumer Super".

The idea is that if you code is consuming the generic values from the object then you should use extends. but if you are producing new values for the generic type you should use super.

So for example:

public void pushAll(Iterable<? extends E> src) {
  for (E e: src) 
    push(e);
}

And

public void popAll(Collection<? super E> dst) {
  while (!isEmpty())
    dst.add(pop())
}

But really you should check out this book: http://java.sun.com/docs/books/effective/

Solution 6 - Java

You might want to google for the terms contravariance (<? super E>) and covariance (<? extends E>). I found that the most useful thing when comprehending generics was for me to understand the method signature of Collection.addAll:

public interface Collection<T> {
    public boolean addAll(Collection<? extends T> c);
}

Just as you'd want to be able to add a String to a List<Object>:

List<Object> lo = ...
lo.add("Hello")

You should also be able to add a List<String> (or any collection of Strings) via the addAll method:

List<String> ls = ...
lo.addAll(ls)

However you should realize that a List<Object> and a List<String> are not equivalent and nor is the latter a subclass of the former. What is needed is the concept of a covariant type parameter - i.e. the <? extends T> bit.

Once you have this, it's simple to think of scenarios where you want contravariance also (check the Comparable interface).

Solution 7 - Java

Before the answer; Please be clear that

  1. Generics only compile time feature to ensure TYPE_SAFETY, it wont b available during RUNTIME.
  2. Only a reference with Generics will force the type safety; if the reference don't declared with generics then it will work without type safty.

Example:

List stringList = new ArrayList<String>();
stringList.add(new Integer(10)); // will be successful.

Hope this will help you to understand wildcard more clear.

//NOTE CE - Compilation Error
//      4 - For

class A {}

class B extends A {}

public class Test {

    public static void main(String args[]) {

		A aObj = new A();
		B bObj = new B();
		
		//We can add object of same type (A) or its subType is legal
		List<A> list_A = new ArrayList<A>();
		list_A.add(aObj);
		list_A.add(bObj); // A aObj = new B(); //Valid
		//list_A.add(new String()); Compilation error (CE);
		//can't add other type   A aObj != new String();
		 
		
		//We can add object of same type (B) or its subType is legal
		List<B> list_B = new ArrayList<B>();
		//list_B.add(aObj); CE; can't add super type obj to subclass reference
		//Above is wrong similar like B bObj = new A(); which is wrong
		list_B.add(bObj);
		
		

        //Wild card (?) must only come for the reference (left side)
		//Both the below are wrong;   
		//List<? super A> wildCard_Wrongly_Used = new ArrayList<? super A>();
		//List<? extends A> wildCard_Wrongly_Used = new ArrayList<? extends A>();
		
		
		//Both <? extends A>; and <? super A> reference will accept = new ArrayList<A>
		List<? super A> list_4__A_AND_SuperClass_A = new ArrayList<A>();
                        list_4__A_AND_SuperClass_A = new ArrayList<Object>();
		              //list_4_A_AND_SuperClass_A = new ArrayList<B>(); CE B is SubClass of A
		              //list_4_A_AND_SuperClass_A = new ArrayList<String>(); CE String is not super of A  


		List<? extends A> list_4__A_AND_SubClass_A = new ArrayList<A>();
		                  list_4__A_AND_SubClass_A = new ArrayList<B>();
		                //list_4__A_AND_SubClass_A = new ArrayList<Object>(); CE Object is SuperClass of A
		                  
		                  
		//CE; super reference, only accepts list of A or its super classes.
		//List<? super A> list_4__A_AND_SuperClass_A = new ArrayList<String>(); 
		                  
		//CE; extends reference, only accepts list of A or its sub classes.
		//List<? extends A> list_4__A_AND_SubClass_A = new ArrayList<Object>();
		                  
		//With super keyword we can use the same reference to add objects
		//Any sub class object can be assigned to super class reference (A)                  
		list_4__A_AND_SuperClass_A.add(aObj);
		list_4__A_AND_SuperClass_A.add(bObj); // A aObj = new B();
		//list_4__A_AND_SuperClass_A.add(new Object()); // A aObj != new Object(); 
		//list_4__A_AND_SuperClass_A.add(new String()); CE can't add other type
		
        //We can't put anything into "? extends" structure. 
		//list_4__A_AND_SubClass_A.add(aObj); compilation error
		//list_4__A_AND_SubClass_A.add(bObj); compilation error
		//list_4__A_AND_SubClass_A.add("");   compilation error
    
        //The Reason is below        
        //List<Apple> apples = new ArrayList<Apple>();
        //List<? extends Fruit> fruits = apples;
        //fruits.add(new Strawberry()); THIS IS WORNG :)
    
        //Use the ? extends wildcard if you need to retrieve object from a data structure.
        //Use the ? super wildcard if you need to put objects in a data structure.
        //If you need to do both things, don't use any wildcard.

		
		//Another Solution
		//We need a strong reference(without wild card) to add objects 
		list_A = (ArrayList<A>) list_4__A_AND_SubClass_A;
		list_A.add(aObj);
		list_A.add(bObj);
		
		list_B = (List<B>) list_4__A_AND_SubClass_A;
		//list_B.add(aObj); compilation error
		list_B.add(bObj);

        private Map<Class<? extends Animal>, List<? extends Animal>> animalListMap;

        public void registerAnimal(Class<? extends Animal> animalClass, Animal animalObject) {
	
		    if (animalListMap.containsKey(animalClass)) {
			    //Append to the existing List
                 /*    The ? extends Animal is a wildcard bounded by the Animal class. So animalListMap.get(animalObject);
                 could return a List<Donkey>, List<Mouse>, List<Pikachu>, assuming Donkey, Mouse, and Pikachu were all sub classes of Animal. 
                 However, with the wildcard, you are telling the compiler that you don't care what the actual type is as long as it is a sub type of Animal.      
                 */   
			    //List<? extends Animal> animalList = animalListMap.get(animalObject);
			    //animalList.add(animalObject);  //Compilation Error because of List<? extends Animal>
                List<Animal> animalList = animalListMap.get(animalClass);
	    		animalList.add(animalObject);      


		    } 
	}

	}
}

Solution 8 - Java

A wildcard with an upper bound looks like " ? extends Type " and stands for the family of all types that are subtypes of Type , type Type being included. Type is called the upper bound .

A wildcard with a lower bound looks like " ? super Type " and stands for the family of all types that are supertypes of Type , type Type being included. Type is called the lower bound .

Solution 9 - Java

You have a Parent class and a Child class inherited from Parent class.The Parent Class is inherited from another class called GrandParent Class.So Order of inheritence is GrandParent > Parent > Child. Now, < ? extends Parent > - This accepts Parent class or either Child class < ? super Parent > - This accepts Parent class or either GrandParent class

Solution 10 - Java

super: List 'super' guarantees object to be ADDED to the collection is of type T.

extends: List 'extend' guarantees object READ from collection is of type T.

Explanation:

There are three things that need to be considered while understanding a difference between 'super' and 'extends' from type safety point of view.

1.Assigning : What type of collection can be assigned to the generic reference.

2.Adding : What type can be added to the collection referred.

3.Reading : What type can be read from collection referred

'' ensures-

  1. Any collection of type T or its superclass can be assigned.

  2. Any object of type T or its subclass can be added to collection, as it will always pass a 'Is A' test for T.

  3. Type of the item read from the collection can not be guarantied except from being of type 'Object'. It can be anything of type T or its superclass which includes type 'Object'.

'' ensures-

  1. Any collection of type T or its subclass can be assigned.

  2. No object can be added as we can not determine type of reference. (Even object of type 'T' can not be added, because generic reference might be assigned to the collection of subtype of 'T')

  3. Item read from the collection can be guarantied to be of type 'T'.

Consider class hierarchy

class Base {}

class Intermediate extends Base{}

class ThirdLayer extends Intermediate{}

public void testGenerics() {

	/**
	 * super: List<? super T> super guarantees object to be ADDED to the collection
	 * if of type T.
	 * 
	 * extends: List<? extends T> extend guarantees object READ from collection is
	 * of type T
	 * 
	 * Super:- 
	 * 
	 * Assigning : You can assign collection of Type T or its super classes
	 * including 'Object' class.
	 * 
	 * Adding: You can add objects of anything of Type T or of its subclasses, as we
	 * are sure that the object of type T of its subclass always passes Is A test
	 * for T. You can NOT add any object of superclass of T.
	 * 
	 * Reading: Always returns Object
	 */

	/**
	 * To a Collection of superclass of Intermediate we can assign Collection of
	 * element of intermediate or its Parent Class including Object class.
	 */
	List<? super Intermediate> lst = new ArrayList<Base>(); 
	lst = new ArrayList<Intermediate>();
	lst = new ArrayList<Object>();

	//Can not assign Collection of subtype
	lst = new ArrayList<ThirdLayer>(); //Error! 

	/** 
	 * Elements of subtype of 'Intemediate' can be added as assigned collection is
	 * guaranteed to be of type 'Intermediate
	 */
	
	lst.add(new ThirdLayer()); 

	lst.add(new Intermediate()); 
	
	// Can not add any object of superclass of Intermediate
	lst.add(new Base()); //Error!

	Object o = lst.get(0);
	
	// Element fetched from collection can not inferred to be of type anything
	// but 'Object'.
	Intermediate thr = lst.get(0); //Error!

	/**
	 * extends: List<? extends T> extend guarantees object read from collection is
	 * of type T 
	 * Assigning : You can assign collection of Type T or its subclasses.
	 * 
	 * Adding: You cannot add objects of anything of Type T or even objects of its
	 * subclasses. This is because we can not be sure about the type of collection
	 * assigned to the reference. 
	 * 
	 * Reading: Always returns object of type 'T'
	 */
	
	// Can assign collection of class Intermediate or its subclasses.
	List<? extends Intermediate> lst1 = new ArrayList<ThirdLayer>();
	lst1 = new ArrayList<Base>(); //Error! can not assign super class collection
	
	/**
	 *  No element can be added to the collection as we can not be sure of
	 *  type of the collection. It can be collection of Class 'Intermediate'
	 *  or collection of its subtype. For example if a reference happens to be 
	 *  holding a list of class ThirdLayer, it should not be allowed to add an
	 *  element of type Intermediate. Hence no addition is allowed including type
	 *  'Intermediate'. 
	 */
	
	lst1.add(new Base()); //Error!
	lst1.add(new ThirdLayer()); //Error!
	lst1.add(new Intermediate()); //Error!

	
	/**
	 * Return type is always guaranteed to be of type 'Intermediate'. Even if the
	 * collection hold by the reference is of subtype like 'ThirdLayer', it always
	 * passes the 'IS A' test for 'Intermediate'
	 */
	Intermediate elm = lst1.get(0); 

	/**
	 * If you want a Collection to accept (aka to be allowed to add) elements of
	 * type T or its subclasses; simply declare a reference of type T i.e. List<T>
	 * myList;
	 */

	List<Intermediate> lst3 = new ArrayList<Intermediate>();
	lst3 = new ArrayList<ThirdLayer>(); //Error!
	lst3 = new ArrayList<Base>(); //Error!

	lst3.add(new Intermediate()); 
	lst3.add(new ThirdLayer());  // Allowed as ThirdLayer passes 'IS A' for Intermediate
	lst3.add(new Base()); //Error! No guarantee for superclasses of Intermediate
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTomasz BłachowiczView Question on Stackoverflow
Solution 1 - JavaJon SkeetView Answer on Stackoverflow
Solution 2 - JavaEdwin DalorzoView Answer on Stackoverflow
Solution 3 - JavaDavid MolesView Answer on Stackoverflow
Solution 4 - JavaM SachView Answer on Stackoverflow
Solution 5 - JavacodefingerView Answer on Stackoverflow
Solution 6 - Javaoxbow_lakesView Answer on Stackoverflow
Solution 7 - JavaKanagavelu SugumarView Answer on Stackoverflow
Solution 8 - JavavinaynagView Answer on Stackoverflow
Solution 9 - JavaCroxView Answer on Stackoverflow
Solution 10 - JavaMahesh HendreView Answer on Stackoverflow