Wildcards

| Saturday, March 20, 2010

Consider the problem of writing a routine that prints out all the elements in a collection.
Here’s how you might write it in an older version of the language:

void printCollection(Collection c) {
Iterator i = c.iterator();
for (k = 0; k < c.size(); k++) {
System.out.println(i.next());
}}


And here is a naive attempt at writing it using generics (and the new for loop syntax):
void printCollection(Collection< Object > c) {
for (Object e : c) {
System.out.println(e);
}}

The problem is that this new version is much less useful than the old one. Whereas
the old code could be called with any kind of collection as a parameter, the new code
only takes Collection< Object >, which, as we’ve just demonstrated, is not a supertype
of all kinds of collections!
So what is the supertype of all kinds of collections? It’s written Collection
(pronounced “collection of unknown”) , that is, a collection whose element type matches
anything. It’s called a wildcard type for obvious reasons. We can write:
void printCollection(Collection c) {
for (Object e : c) {
System.out.println(e);
}}
and now, we can call it with any type of collection. Notice that inside printCollection(),
we can still read elements from c and give them type Object. This is always
safe, since whatever the actual type of the collection, it does contain objects. It isn’t
safe to add arbitrary objects to it however:
Collection c = new ArrayList();
c.add(new Object()); // compile time error
Since we don’t know what the element type of c stands for, we cannot add objects
to it. The add() method takes arguments of type E, the element type of the collection.
When the actual type parameter is ?, it stands for some unknown type. Any parameter
we pass to add would have to be a subtype of this unknown type. Since we don’t know
what type that is, we cannot pass anything in. The sole exception is null, which is a
member of every type.
On the other hand, given a List, we can call get() and make use of the result.
The result type is an unknown type, but we always know that it is an object. It is
therefore safe to assign the result of get() to a variable of type Object or pass it as a
parameter where the type Object is expected.

0 comments:

Post a Comment