List<?>
represents a list of some arbitrary type, with greater type safety than List<Object>
.Bounded wildcards allow you to specify a type parameter as an arbitrary subtype or supertype of a specified class. So,
List<?extends E>
represents a list of some subtype of E
, and List<? super E>
represents a list of somesupertype of E
. (Note that the subtype relation is defined so that Number
is a subtype of itself.)As noted in Item 25, generic types are invariant. Given two type
B
andD
where D
is a subtype B
, List<D>
is not a subtype of List<B>
. This can give rise to unfortunate restrictions. Considering the Stack class previously used as an example - you can invoke push(intVal)
on a Stack<Number>
where intVal
is an Integer
, because Integer
is a subtype of Number
. You can also store the return value of pop()
in an Object
, because Object
is asupertype of Number
.However, extending the
Stack
class to include methods to push
and pop
sequences of elements runs into a snag:
public void pushAll(Iterable<E> src) {...}
public void popAll(Collection<E> dst) {...}
These won't do; while they compile, they will only work with collections which exactly match the stack's element type. With our
Stack<Number>
, passing a sequence of Integers topopAll()
will fail, as will passing a sequence of Objects
to popAll()
. The solution is to use bounded wildcards:
public void pushAll(Iterable<? extends E> src) {...}
public void popAll(Collection<? super E> dst) {...}
The
pushAll()
method can now be passed a sequence of any type which isa subtype of the stack's type parameter. Likewise, the argument to
pushAll()
, which is effectively an out parameter, may now be a sequence of any type which is a supertype of the stack's type parameter. In other words, for a Stack<Number>
, you can pop sequences of Integers
, and push sequences of Objects.Josh introduces a mnemonic to remember which type of wildcard type to use: PECS, standing for Producer-Extends, Consumer-Super. This is not the most snappy and memorable mnemonic I've ever heard, but if it helps people then fine. I prefer the Get-Put Principle which Josh refers to but does not quote:
"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 do both."
Note that
popAll()
defines a parameter rather than a return type. Thisallows the wildcard types to be as unobtrusive to the user of the class as possible. If a wildcard type was used as a return type, users of the class would be used to wildcard types in their own code.
After demonstrating the use of wildcard types with some of the methods from previous items, Josh rounds off with a neat little technique - though it does not relate specifically to boundedwildcards . Using the example of a swap() method, he demonstrates that the method could be declared using an unbounded type parameter or an unboundedwildcard. The wildcard version clearly presents a cleaner, simpler interface and so should be used in a public API. However the implementation of the type parameter version is much more straightforward. Happily the tension here can be resolved by making the type parameter version a private helper method, to which the public method forwards, with thewildcard type being captured in the process.
Ewan Milne