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."