0
0
JavaComparisonBeginner · 4 min read

Upper Bounded vs Lower Bounded Wildcard in Java: Key Differences

In Java, an upper bounded wildcard (e.g., ? extends Type) restricts the unknown type to be a subtype of Type, allowing you to read from a generic structure safely. A lower bounded wildcard (e.g., ? super Type) restricts the unknown type to be a supertype of Type, enabling safe writes to a generic structure.
⚖️

Quick Comparison

Here is a quick side-by-side comparison of upper bounded and lower bounded wildcards in Java generics.

AspectUpper Bounded Wildcard (? extends Type)Lower Bounded Wildcard (? super Type)
Type RestrictionUnknown type must be a subtype of TypeUnknown type must be a supertype of Type
UsageSafe to read items as Type or its subtypeSafe to write items of Type or its subtype
Read/WriteAllows reading, restricts writing (except null)Allows writing, restricts reading (except Object)
ExampleList<? extends Number>List<? super Integer>
Common Use CaseCovariance - when you want to read from a genericContravariance - when you want to write to a generic
⚖️

Key Differences

An upper bounded wildcard uses the syntax ? extends Type and means the generic type can be Type or any subclass of it. This is useful when you want to read data from a generic collection safely as Type or its subtype, but you cannot add new elements (except null) because the exact subtype is unknown.

In contrast, a lower bounded wildcard uses ? super Type and means the generic type can be Type or any superclass of it. This allows you to add elements of Type or its subclasses safely, but reading from the collection only guarantees an Object type, since the exact supertype is unknown.

In summary, ? extends is for covariance (safe reading), and ? super is for contravariance (safe writing). This distinction helps maintain type safety while allowing flexibility in generic programming.

⚖️

Code Comparison

This example shows how an upper bounded wildcard allows reading numbers safely but restricts adding new elements.

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

public class UpperBoundedExample {
    public static void printNumbers(List<? extends Number> list) {
        for (Number num : list) {
            System.out.println(num);
        }
        // list.add(10); // Compile error: cannot add to List<? extends Number>
    }

    public static void main(String[] args) {
        List<Integer> ints = new ArrayList<>();
        ints.add(1);
        ints.add(2);
        printNumbers(ints);
    }
}
Output
1 2
↔️

Lower Bounded Wildcard Equivalent

This example shows how a lower bounded wildcard allows adding integers safely but restricts reading to Object type.

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

public class LowerBoundedExample {
    public static void addIntegers(List<? super Integer> list) {
        list.add(10);
        list.add(20);
        // Integer num = list.get(0); // Compile error: cannot guarantee Integer type on get
        Object obj = list.get(0); // Allowed, returns Object
        System.out.println(obj);
    }

    public static void main(String[] args) {
        List<Number> numbers = new ArrayList<>();
        addIntegers(numbers);
    }
}
Output
10
🎯

When to Use Which

Choose ? extends Type (upper bounded wildcard) when you want to read data from a generic structure and do not need to add new elements. This is common when you want to process or display data safely.

Choose ? super Type (lower bounded wildcard) when you want to add elements to a generic structure but do not care about the exact type when reading. This is useful when you build or modify collections.

Remember: use upper bounded wildcards for covariance (read-only), and lower bounded wildcards for contravariance (write-only).

Key Takeaways

Use ? extends Type to safely read from generics but avoid adding elements.
Use ? super Type to safely add elements to generics but reading returns Object.
Upper bounded wildcards support covariance (subtyping for reading).
Lower bounded wildcards support contravariance (supertyping for writing).
Choosing the right wildcard improves type safety and flexibility in Java generics.