When to use wildcards in Java Generics?
Wild cards are about co/contra variance of generics. I will try to make clear what this means by providing some examples.
Basically it is related to the fact that for types S and T, where S is a subtype of T, a generic type G<S>
is not a valid subtype of G<T>
List<Number> someNumbers = new ArrayList<Long>(); // compile error
You can remedy this with wild cards
List<? extends Number> someNumbers = new ArrayList<Long>(); // this works
Please note, that you can not put anything into such a list
someNumbers.add(2L); //compile error
even (and more surprising for many developers):
List<? extends Long> someLongs = new ArrayList<Long>();
someLongs.add(2L); // compile error !!!
I think SO is not the right place to discuss that in detail. I will try to find some of the articles and papers that explain this in more detail.
The big difference between
public <T extends Animal> void takeThing(ArrayList<T> list)
and
public void takeThing(ArrayList<? extends Animal> list)
is that in the former method you can refer to "T" within the method as the concrete class that was given. In the second method you cannot do this.
Here a more complex example to illustrate this:
// here i can return the concrete type that was passed in
public <T extends Animal> Map<T, String> getNamesMap(ArrayList<T> list) {
Map<T, String> names = new HashMap<T, String>();
for (T animal : list) {
names.put(animal, animal.getName()); // I assume there is a getName() method
}
return names;
}
// here i have to use general Animal
public Map<Animal, String> getNamesMap(ArrayList<? extends Animal> list) {
Map<Animal, String> names = new HashMap<Animal, String>();
for (Animal animal : list) {
names.put(animal, animal.getName()); // I assume there is a getName() method
}
return names;
}
With the first method if you pass in an List of Cats you get a Map with Cat as key. The second method would always return a Map with general Animal key.
By the way this is not valid java syntax:
public <? extends Animal> void takeThing(ArrayList<?> list)
Using this form of generic method declaration you have to use a valid java identifier and not "?".
Edit:
The form "? extends Type" only applies to variable or parameter type declaration. Within a generic method declration it has to be "Identifier extends Type" as you are able to refer to the "Identifier" from within your method.