The wildcards introduce restrictions in how the collection can be used.
For example, with List<? extends Number>
, I can't add new elements to the list. This is because all I know is that the list is some kind of subtype of Number
, but I don't know what that actual subtype is (so how could I know what to add?). For example, take the following code:
public void doSomethingWith(List<? extends Number> numbers) {
numbers.add(Integer.valueOf(0)); // Won't compile
}
This won't compile because both of these method calls are legal:
doSomethingWith(new ArrayList<Integer>());
doSomethingWith(new ArrayList<Double>());
What you can do is read elements from the list:
// This will all compile
public void doSomethingWith(List<? extends Number> numbers) {
for (Number number : numbers) {
// Do something with number
}
// OR
Number number = numbers.get(0);
// OR
Number number = numbers.remove(0);
}
Calls to methods like get
will return some kind of Number
, we know that for a fact because of the ? extends Number
, so we can treat it like that for reading purposes.
On the other hand, List<? super Integer>
has exactly the opposite result. I can no longer read from the list, but I can write to it. I know that whatever ?
is, it will definitely be a super-class of Integer
, so concrete types of the list will definitely accept Integer
values. For example:
public void doSomethingWith(List<? super Integer> integers) {
integers.add(Integer.valueOf(0));
}
That code is completely legal. However, if you want to read from the list, the only way to do this is to use Object
since anything else requires casting (which requires knowing its concrete type):
for (Object obj : integers)
// OR
Object obj = integers.get(0);
// OR
Object obj = integers.remove(0);
What's Really Happening
Here's what's actually happening. When you specify ? extends Number
, you're making any method that takes elements as a parameter unusable. In fact, if you try to auto-complete code in Eclipse using Ctrl+Space on a List<? extends Number>
, it shows null
as the parameters' types in the add
methods and the like. Meanwhile, all the methods that return elements are guaranteed to return at least some kind of Number
, though you won't know exactly which subclass of Number
it might actually be.
When you specify ? super Integer
, you're making any method that takes elements as a parameter guarantee that they'll accept Integer
values (and sub-classes of Integer
as well). This allows you to call methods like add
since you know they'll accept Integer
types. Meanwhile, all methods that return elements are only guaranteed to return something, but we don't know what, so all the methods that return elements are only guaranteed to return Object
.
PECS is an excellent acronym to remember this, it means "Producer Extends, Consumer Supers". This means that if you want your list to give you something, it's a producer, and you should use extends
. If you want your list to accept things from you, it's a consumer, so you use super
. See this answer for more.
But what if I have a wildcard with no bounds?
It does both! <?>
restricts you from calling methods that take the generic type as an argument and causes all the methods that return the generic type to return Object
. This is because we have no idea what the type is whatsoever. For example, all of these assignments into a List<?>
are legal:
List<?> list;
list = new ArrayList<Integer>();
list = new ArrayList<String>();
list = new ArrayList<MyClass>();
And so on.