Skip to content
Home » Java generics extends vs super

Java generics extends vs super

  • by
Java generics extends vs super

1. Overview

In this article, we will learn the differences between Java generics extends vs super. To learn more about other Java topics, refer to these articles.

2. Java generics extends vs super (PECS)

Java generics follow the “PECS” (Producer – extends and Consumer – super) principle.

  1. Producer – If you want to only retrieve the elements from a generic collection, use extends.
  2. Consumer – If you want to only put elements into a generic collection, use super.
  3. If you do both retrieve and put operations with the same collection, you shouldn’t use either extends or super.

2. Java generics extends – Covariance

The Upper Bounded Wildcards restrict the unknown type to be a specific type or a subtype of that type and is represented using the extends keyword. 

List<? extends Number> is an example of a bounded wildcard. The ? stands for an unknown type which is in fact a subtype of Number. Note that it could be Number itself, or some subclass. It need not literally extend Number. We can say that Number is the upper bound of the wildcard.

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

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

2.1. Generics extends – Write operation

You can’t add any objects to the extends generics including any subtype such as Integer, Double and super type Number as well.

Look at the below code. We are trying to assign double which results in the compilation error.

List<? extends Number> numberList = new ArrayList<Double>(); numberList.add(10.0); 

The type of the numberList is extends Number, in the sense an unknown subtype of Number. Since we don’t know what type it is and being unknown, we don’t know if it is an Integer, Double. Thus, it prevents assigning values to the extends generics.

Even the below Number assignment is not possible (what if it is a Double).

List<? extends Number> numberList = new ArrayList<Number>();
numberList.add(10);

2.2. Generics extends – Read operation

You can read the values from the extends generics and assign to Number type. Since the values are definitely of type Number, this is allowed.

public class MyClass {
    public static void main(String args[]) {
      List<? extends Number> numberList = getDoubleValues();
      
      Number value = numberList.get(0);
      System.out.println(value);
    }
    
    private static ArrayList<Double> getDoubleValues() {
        ArrayList<Double> doubleList = new ArrayList<Double>();
        doubleList.addAll(Arrays.asList(10.5, 9.5, 7.3));
        return doubleList;
    }
    
    private static ArrayList<Integer> getIntValues() {
        ArrayList<Integer> intList = new ArrayList<Integer>();
        intList.addAll(Arrays.asList(10, 9, 7));
        return intList;
    }
}

However, you can’t assign to subtype variables such as Double or Integer. The type of the numberList is extends Number, in the sense an unknown subtype of Number. Since we don’t know what type it is and being unknown, we can’t assign to subtypes.

public static void main(String args[]) {
      List<? extends Number> numberList = getDoubleValues();
      
      Double value = numberList.get(0); 
      System.out.println(value);
    }

3. Java Generics super

lower bounded wildcard restricts the unknown type to be a specific type or a super type of that type.

We express a lower bounded wildcard using the wildcard character (‘?’), following by the super keyword, followed by its lower bound<? super A>.

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

List<? super Integer> numberList = new ArrayList<Integer>();  
List<? super Integer> numberList = new ArrayList<Number>();   
List<? super Integer> numberList = new ArrayList<Object>();   

3.1. Generics super – Read operation

The type of the numberList is super Integer, in the sense, an unknown supertype of Integer. Since we don’t know what type it is and being unknown, we don’t know if the super type is a Number or Object.

You can’t read the values and assign to Number or Integer as numberList could be holding Number or Object super type.

List<? super Integer> numberList = getIntValues();
Number value = numberList.get(0); 
System.out.println(value);

As we know, it is legal to assign subtype value to a super type. As the Object class doesn’t extend any supertype and Number or Integer are subtypes of an Object, you can retrieve the list value to an Object instance.

Though numberList holds Integer or Number, both are subtypes of Object.

public class MyClass {
    public static void main(String args[]) {
      List<? super Integer> numberList = getIntValues();
      
      Object value = numberList.get(0);
      System.out.println(value);
    }
    
    private static ArrayList<Integer> getIntValues() {
        ArrayList<Integer> intList = new ArrayList<Integer>();
        intList.addAll(Arrays.asList(10, 9, 7));
        return intList;
    }
}

3.2. Generics super – Write operation

You can add an Integer or subclass of Integer to the numberList.

List<? super Integer> numberList = new ArrayList<Object>();
numberList.add(50); 
System.out.println(numberList.get(0));

However, you can’t add Double, Number or Object to the numberList.

List<? super Integer> numberList = new ArrayList<Object>();
      
      Number number = 10;
      numberList.add(number); 
      System.out.println(numberList.get(0));

4. Conclusion

To sum up, we have learned the differences between Java generics extends vs super. You can find code samples in our GitHub repository.

Leave a Reply

Your email address will not be published. Required fields are marked *