posted 16 years ago
Hi,
Its important to know where wildcard with extends or super to be used.
Wildcard with extends
code:
interface Collection<E> {
...
public boolean addAll(Collection<? extends E> c);
...
}
and
// # 1
List<Number> nums = new ArrayList<Number>();
List<Integer> ints = Arrays.asList(1, 2);
List<Double> dbls = Arrays.asList(2.78, 3.14);
nums.addAll(ints);
nums.addAll(dbls);
The first call is permitted because nums has type List<Number>, which is a subtype of Collection<Number>, and ints has type List<Integer>, which is a subtype of Collection<? extends Number>. The second call is similarly permitted. In both calls, E is taken to be Number.So we use ? extends E
We can also use wildcards when declaring variables. #1 changed by adding a wildcard to the second line:
List<Integer> ints = Arrays.asList(1,2);
List<? extends Number> nums = ints;// ok
nums.add(3.14); //compile-time error because you cannot add
//a double to List<? extends Number>, since
//it might be a list of some other subtype of number
assert ints.toString().equals("[1, 2, 3.14]"); //here is why compile-time error
If a structure contains elements with a type of the form ? extends E, we can get elements out of the structure, but we cannot put elements into the structure.
Wildcards with super
Here is a method that copies into a destination list all of the elements from a source list, from the convenience class Collections:
public static <T> void copy(List<? super T> dst, List<? extends T> src) {
for (int i = 0; i < src.size(); i++) {
dst.set(i, src.get(i));
}
}
? 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.
Here is a sample call.
List<Object> objs = Arrays.<Object>asList(2, 3.14, "four");
List<Integer> ints = Arrays.asList(5, 6);
Collections.copy(objs, ints);
assert objs.toString().equals("[5, 6, four]");
As with any generic method, the type parameter may be inferred or may be given explicitly. In this case, there are four possible choices, all of which type-check and all of which have the same effect:
Collections.copy(objs, ints);
Collections.<Object>copy(objs, ints);
Collections.<Number>copy(objs, ints);
Collections.<Integer>copy(objs, ints);
The first call leaves the type parameter implicit; it is taken to be Integer, since that is the most specific choice that works. In the third line, the type parameter T is taken to be Number. The call is permitted because objs has type List<Object>, which is a subtype of List<? super Number> (since Object is a supertype of Number, as required by the super) and ints has type List<Integer>, which is a subtype of List<? extends Number> (since Integer is a subtype of Number, as required by the extends wildcard).
We could also declare the method with several possible signatures.
public static <T> void copy(List<T> dst, List<T> src)
public static <T> void copy(List<T> dst, List<? extends T> src)
public static <T> void copy(List<? super T> dst, List<T> src)
public static <T> void copy(List<? super T> dst, List<? extends T> src)
The first of these is too restrictive, as it only permits calls when the destination and source have exactly the same type. The remaining three are equivalent for calls that use implicit type parameters, but differ for explicit type parameters. For the example calls above, the second signature works only when the type parameter is Object, the third signature works only when the type parameter is Integer, and the last signature works (as we have seen) for all three type parametersi.e., Object, Number, and Integer. Always use wildcards where you can in a signature, since this permits the widest range of calls.
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.
I think this may help you.
[ October 04, 2008: Message edited by: sannuth kashikar ]