? extends vs ? super

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 5 min

TL;DR

  • ? extends T (Upper Bound): Use when you only need to read/get values from a generic structure.
  • ? super T (Lower Bound): Use when you only need to write/put values into a generic structure.

Concept

Choosing between extends and super wildcards is the most difficult part of Java Generics.

The extends wildcard (Covariance)

A List<? extends Number> means “a list of some unknown type, as long as that type is Number or a child of Number”.

  • Reading: Safe. You know for a fact that whatever is inside is at least a Number.
  • Writing: Unsafe. The list might actually be a List<Double>. If you try to add an Integer, it will crash. Thus, writing is forbidden by the compiler.

The super wildcard (Contravariance)

A List<? super Integer> means “a list of some unknown type, as long as that type is Integer or a parent of Integer (like Number or Object)”.

  • Reading: Unsafe. You don’t know what type you will get back (it could be an Object). You can only retrieve data as a raw Object.
  • Writing: Safe. Whether the underlying list is a List<Integer>, List<Number>, or List<Object>, an Integer is a valid child of all of those.

Examples

import java.util.ArrayList;
import java.util.List;

public class ExtendsVsSuper {
    
    // Use EXTENDS when you want to READ from the list
    public static void processNumbers(List<? extends Number> list) {
        for (Number num : list) { // Safe to read as Number
            System.out.println(num.doubleValue()); 
        }
        // list.add(10); // COMPILE ERROR! Cannot write.
    }

    // Use SUPER when you want to WRITE to the list
    public static void populateIntegers(List<? super Integer> list) {
        list.add(10); // Safe to write Integer
        list.add(20);
        
        // Integer i = list.get(0); // COMPILE ERROR! Cannot safely read as Integer.
    }

    public static void main(String[] args) {
        List<Double> doubles = new ArrayList<>(List.of(1.5, 2.5));
        processNumbers(doubles); // Read-only access
        
        List<Number> numbers = new ArrayList<>();
        populateIntegers(numbers); // Write-only access
    }
}

Interview Questions

Q: Can you use ? extends and ? super at the same time?
A: No. You cannot write <? extends Number super Integer>. Java wildcards allow you to define either an upper bound or a lower bound, but not both simultaneously.

Q: What happens if you try to read from a ? super T collection?
A: You can technically read from it, but the compiler will only guarantee that the elements are of type Object. If you have a List<? super Integer>, the compiler knows the list could actually be a List<Object>. Therefore, Object obj = list.get(0); is valid, but Integer i = list.get(0); will cause a compilation error.