Section 2.7. Wildcard Capture


2.7. Wildcard Capture

When a generic method is invoked, the type parameter may be chosen to match the unknown type represented by a wildcard. This is called wildcard capture.

Consider the method reverse in the convenience class java.util.Collections, which accepts a list of any type and reverses it. It can be given either of the following two signatures, which are equivalent:

 public static void reverse(List<?> list); public static void <T> reverse(List<T> list); 

The wildcard signature is slightly shorter and clearer, and is the one used in the library.

If you use the second signature, it is easy to implement the method:

 public static void <T> reverse(List<T> list) {   List<T> tmp = new ArrayList<T>(list);   for (int i = 0; i < list.size(); i++) {     list.set(i, tmp.get(list.size()-i-1));   } } 

This copies the argument into a temporary list, and then writes from the copy back into the original in reverse order.

If you try to use the first signature with a similar method body, it won't work:

 public static void reverse(List<?> list) {   List<Object> tmp = new ArrayList<Object>(list);   for (int i = 0; i < list.size(); i++) {     list.set(i, tmp.get(list.size()-i-1));  // compile-time error   } } 

Now it is not legal to write from the copy back into the original, because we are trying to write from a list of objects into a list of unknown type. Replacing List<Object> with List<?> won't fix the problem, because now we have two lists with (possibly different) unknown element types.

Instead, you can implement the method with the first signature by implementing a private method with the second signature, and calling the second from the first:

 public static void reverse(List<?> list) { rev(list); } private static <T> void rev(List<T> list) {   List<T> tmp = new ArrayList<T>(list);   for (int i = 0; i < list.size(); i++) {     list.set(i, tmp.get(list.size()-i-1));   } } 

Here we say that the type variable T has captured the wildcard. This is a generally useful technique when dealing with wildcards, and it is worth knowing.

Another reason to know about wildcard capture is that it can show up in error messages, even if you don't use the above technique. In general, each occurrence of a wildcard is taken to stand for some unknown type. If the compiler prints an error message containing this type, it is referred to as capture of ?. For instance, with Sun's current compiler, the incorrect version of reverse generates the following error message:

 Capture.java:6: set(int,capture of ?) in java.util.List<capture of ?> cannot be applied to (int,java.lang.Object)             list.set(i, tmp.get(list.size()-i-1));                 ^ 

Hence, if you see the quizzical phrase capture of ? in an error message, it will come from a wildcard type. Even if there are two distinct wildcards, the compiler will print the type associated with each as capture of ?. Bounded wildcards generate names that are even more long-winded, such as capture of ? extends Number.




Java Generics and Collections
Java Generics and Collections
ISBN: 0596527756
EAN: 2147483647
Year: 2006
Pages: 136

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net