JavaGenerics

Wildcards

Sometimes the fact that generics are invariant makes things difficult. Imagine the code:


class ArrayList<E> implements List<E> {
    ...
    boolean addAll(Collection<E> c) {...}
    ...
}

List<String> strings = new ArrayList<>();
List<Object> objects = new ArrayList<>();

objects.addAll(strings); // compile-time error!

This code would not compile since List is a subclass of Collection but List<String> is not a subclass of List<Object>!

Despite it is perfectly safe to add strings elements to objects collection, addAll method signature prohibits this.

To improve the situation wildcards could be used.

Wildcard has the form:

? extends ReferenceType
? super ReferenceType


If S is a subtype of T then type List<S> is considered to be a subtype of List<? extends T>.

If S is a supertype of T then List<S> is considered to be a subtype of List<? super T>.

With wildcards code from the first step has the form:

class ArrayList<E> implements List<E> {
    ...
    // Anything more special than E could be added into the list as well as E
    boolean addAll(Collection<? extends E> c) { ... }
    ...
}

List<String> strings = new ArrayList<>();
List<Object> objects = new ArrayList<>();

objects.addAll(strings); // completly fine (all Strings are objects)!
strings.addAll(objects); // compile time error (not all Objects are Strings) !

With wildcards it's possible to add string elements to object collection but not vice versa. It's reasonable, since String is subtype of Object (String extends Object), but Object is not subtype of String.

To detect whether extends or super should be used it's worth to remember the Get and Put principle:

The Get and Put Principle: use an extends wildcard when you only get values out of a structure, use a super wildcard when you only put values into a structure, and don’t use a wildcard when you both get and put.

In the previous example we took elements out of c collection, so we use extends keyword.

Let's look at the examples from java.util.Collections:

Method unmodifiableList creates new List object reading objects from the list provided:

public static <T> List<T> unmodifiableList(List<? extends T> list)
According to Put and Get principle extends is used since we consuming elements from original list. This makes possible to create unmodifiable list of numbers using list of integers:
List<Number> numbers = Collections.<Number>unmodifiableList(new ArrayList<Integer>());

When used in fill method, the list is used only to put elements in it, that's why super is used.

public static <T> void fill(List<? super T> list, T obj) { ... }

Using super makes perfectly fine to use fill as:

// Since Interger is a subtype of Number we can guarantee that newly created array will have only Numbers in it
Collections.<Integer>fill(new ArrayList<Number>, new Integer(10));

Please also note the explicit definition of the type parameter in both cases (not necessary here, just for illustration).

The Get and Put Principle works in the opposite direction as well: if the structure is declared with extends you can only get values from it. If it's declared with super – you can only put values into it. The compiler knows about this:


List<? extends Number> list = new ArrayList<>();
list.add(0); // Get and Put principle violation, compile-time error!


And that's why:

class Example {
  public static void addToList(List<? extends Number> numbers) {
        // If we will allow addition to the list both should be allowed
        numbers.add(5);
        numbers.add(1.5);
    }
}

public class Main {
  public static void main(String[] args) {

    List<Integer> integers = new ArrayList<>();    
    // We introduced wildcards to be able to do things like this
    Example.addToList(integers);

    // The integer is... a double. But that's nonsense!
    Integer nonsense = integers.get(1);     
  }
}

As we see, ability to add to structure declared with extends leads to nonsense.

The frequently used unbounded wildcard:
?
is equivalent to:
? extends Object
How did you like the theory?
Report a typo