Since the class shape itself matches extends shape
CHAPTER 10. GENERIC PROGRAMMING AND COLLECTION CLASSES 519
in the Comparable interface. What we need is a way of specifying that a generic class or method only applies to objects of type Comparable and not to arbitrary objects. With that restriction, we should be free to use compareTo() in the definition of the generic class or method.
This method works fine if we apply it to a variable of type Collection<Shape>, or Ar-rayList<Shape>, or any other collection class with type parameter Shape. Suppose, however, that you have a list of Rects stored in a variable named rectangles of type Collection<Rect>. Since Rects are Shapes, you might expect to be able to call drawAll(rectangles). Unfortu-nately, this will not work; a collection of Rects is not considered to be a collection of Shapes! The variable rectangles cannot be assigned to the formal parameter shapes. The solution is to replace the type parameter “Shape” in the declaration of shapes with the wildcard type“? extends Shape”:
public static void drawAll(Collection<? extends Shape> shapes) { for ( Shape s : shapes )
s.draw();
}
Suppose that rectangles is of type List<Rect>. It’s illegal to
call addOval(rectangles,oval), because of the rule that a list of Rects
is not a list of Shapes. If we dropped that rule, then
addOval(rectangles,oval) would be legal, and it would add an Oval to a
list of Rects. This would be bad: Since Oval is not a subclass of Rect,
an Oval is not a Rect, and a list of Rects should never be able to
contain an Oval. The method call addOval(rectangles,oval) does not make
sense and should be illegal, so the rule that a collection of Rects is
not a collection of Shapes is a good rule.)
As another example, consider the method addAll() from the interface
Collection<T>. In my description of this method in Subsection
10.1.4, I say that for a collection, coll, of type Collection<T>,
coll.addAll(coll2) “adds all the objects in coll2 to coll. The
parameter, coll2, can be any collection of type Collection<T>.
However, it can also be more general. For example, if T is a class and S
is a sub-class of T, then coll2 can be of type Collection<S>. This
makes sense because any object of type S is automatically of type T and
so can legally be added to coll.” If you think for a moment, you’ll see
that what I’m describing here, a little awkwardly, is a use of wildcard
types: We don’t want to require coll2 to be a collection of of objects
of type T; we want to allow collections of any subclass of T. To be more
specific, let’s look at how a similar addAll() method could be added to
the generic Queue class that was defined earlier in this section:
class Queue<T> {
private LinkedList<T> items = new LinkedList<T>();
public void enqueue(T item) {
items.addLast(item);
}
public T dequeue() {
return items.removeFirst();
}
public boolean isEmpty() {
return (items.size() == 0);
}
public void addAll(Collection<? extends T> collection) {
// Add all the items from the collection to the end of the queue for ( T item : collection )
enqueue(item);
}
}