Java Subtyping & Wildcards
October 11th, 2009.Filed under Programming.

Arrays like Integer[] is a subtype of Number[] but List< Integer > is not a subtype of List< Number >. We would like lists to behave more like arrays, in that we want to accept not only a list with elements of a given type, but also a list with elements of any subtype of a given type. We then have to use wildcards.
... public boolean addAll(Collections< ? extends E > c); ... // Used like so List< Number > numbers = new ArrayList< Number >(); List< Double > doubleNumbers = Arrays.asList(2.78, 3.14); List< Integer > integerNumbers = Arrays.asList(1, 2); numbers.addAll(doubleNumbers); numbers.addAll(integerNumbers); // numbers list will then have : [1, 2, 2.78, 3.14]
“? extends E” means that it is also OK to add all members of a collection with elements of any type that is a subtype of E.
If a list contains elements with a type of the form ? extends E, we can get elements out of the list, but we cannot put elements into the list. To put elements into the structure we need another kind of wildcard which is defined by using List < ? super T >.
public static < T > void copyThis(List< ? super T > destinationList, List< ? extends T > sourceList) {
for (int i = 0; i < sourceList.size(); i++) {
destinationList.set(i, sourceList.get(i));
}
}
// can be used like so:
List< Object > myObjects = Arrays.< Object >asList(2, 3.14, "Millad","Dagdoni");
List< Integer > myIntegers = Arrays.asList(9, 8,0);
copyThis(myObjects, myIntegers);
? super T means that the destination list may have elements of any type that is a supertype of T, just as the source list may have elements of any type that is a subtype of T.
Where should you use extends, where should you use super ?
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.
Here is a method that takes a collection of numbers, converts each to a double, and sums them up like so:
public static double sumNumbers(Collection< ? extends Number > myNums) {
double theSum = 0.0;
for (Number num : myNums) theSum += num.doubleValue();
return theSum;
}
Since this uses extends, all of the following calls are legal:
List< Integer > ints = Arrays.asList(1,2,3); System.out.println( sum(ints) == 6.0 ); List< Double > doubles = Arrays.asList(2.78,3.14); System.out.println( sum(doubles) == 5.92 ); List< Numbe r> nums = Arrays.< Number >asList(1,2,2.78,3.14); System.out.println( sum(nums) == 8.92 );
The first two calls would not be legal if extends was not used.
Whenever you use the add method, you put values into a structure, so use a super wildcard. Here is a method that takes a collection of numbers and an integer n, and puts the first n integers, starting from zero, into the collection:
public static void countNumbers(Collection super Integer> ints, int n) {
for (int i = 0; i < n; i++) ints.add(i);
}
This uses super, all of the following calls are legal:
List< Integer > ints = new ArrayList< Integer >();
count(ints, 5);
System.out.println( ints.toString().equals("[0, 1, 2, 3, 4]") );
List< Number > nums = new ArrayList< Number >();
count(nums, 5); nums.add(5.0);
System.out.println( nums.toString().equals("[0, 1, 2, 3, 4, 5.0]") );
List< Object > objs = new ArrayList< Object >();
count(objs, 5); objs.add("five");
System.out.println( objs.toString().equals("[0, 1, 2, 3, 4, five]") );
The last two calls would not be legal if super was not used.
