Difference between generic type and wildcard type

Fio picture Fio · Jun 8, 2012 · Viewed 19.8k times · Source

I'm a newbie in Generic and my question is: what difference between two functions:

function 1:

public static <E> void funct1  (List<E> list1) {

}

function 2:

public static void funct2(List<?> list) {

}

Answer

Jens Schauder picture Jens Schauder · Jun 8, 2012

The first signature says: list1 is a List of Es.

The second signature says: list is a List of instances of some type, but we don't know the type.

The difference becomes obvious when we try to change the method so it takes a second argument, which should be added to the list inside the method:

import java.util.List;

public class Experiment {
    public static <E> void funct1(final List<E> list1, final E something) {
        list1.add(something);
    }

    public static void funct2(final List<?> list, final Object something) {
        list.add(something); // does not compile
    }
}

The first one works nicely. And you can't change the second argument into anything that will actually compile.

Actually I just found an even nicer demonstration of the difference:

public class Experiment {
    public static <E> void funct1(final List<E> list) {
        list.add(list.get(0));
    }

    public static void funct2(final List<?> list) {
        list.add(list.get(0)); // !!!!!!!!!!!!!! won't compile !!!!!!!!!
    }
}

One might as why do we need <?> when it only restricts what we can do with it (as @Babu_Reddy_H did in the comments). I see the following benefits of the wildcard version:

  • The caller has to know less about the object he passes in. For example if I have a Map of Lists: Map<String, List<?>> I can pass its values to your function without specifying the type of the list elements. So

  • If I hand out objects parameterized like this I actively limit what people know about these objects and what they can do with it (as long as they stay away from unsafe casting).

These two make sense when I combine them: List<? extends T>. For example consider a method List<T> merge(List<? extends T>, List<? extends T>), which merges the two input lists to a new result list. Sure you could introduce two more type parameters, but why would you want to? It would be over specifying things.

  • finally wildcards can have lower bounds, so with lists you can make the add method work, while get doesn't give you anything useful. Of course that triggers the next question: why don't generics have lower bounds?

For a more in depth answer see: When to use generic methods and when to use wild-card? and http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#FAQ203