I think this section of Generics Tutorial explains the situation (my emphasis):
"You need to make certain that the generic API is not unduly restrictive; it must
continue to support the original contract of the API. Consider again some examples
from java.util.Collection. The pre-generic API looks like:
interface Collection {
public boolean containsAll(Collection c);
...
}
A naive attempt to generify it is:
interface Collection<E> {
public boolean containsAll(Collection<E> c);
...
}
While this is certainly type safe, it doesn’t live up to the API’s original contract.
The containsAll() method works with any kind of incoming collection. It will only
succeed if the incoming collection really contains only instances of E, but:
- The static type of the incoming
collection might differ, perhaps
because the caller doesn’t know the
precise type of the collection being
passed in, or perhaps because it is a
Collection<S>,where S is a
subtype of E.
- It’s perfectly
legitimate to call containsAll() with
a collection of a different type. The
routine should work, returning false."