Wildcards and Generic Methods in Java (Page 1 of 5 )
We saw the extends construct used to specify an upper bound for both type variables and wildcard instantiations. It implies a type that is "at the top" of the object hierarchy for the bound. Wildcard instantiations actually allow another type of bound called a lower bound as well. A lower bound is specified with the keyword super and, as you might guess, requires that instantiations be of a certain type or any of its supertypes, up to Object. For example:
List< ? super MyDate > listOfAssignableFromMyDate; listOfAssignableFromMyDate = new ArrayList<MyDate>(); listOfAssignableFromMyDate = new ArrayList<Date>(); listOfAssignableFromMyDate = new ArrayList<Object>();
This wildcard instantiation creates a type that can hold any instantiation of List on the type MyDate or any of its supertypes. In our example world, that means the wildcard type can be assigned one of only three types: List<MyDate>, List<Date>, or List<Object>. Here, we have cut off the object inheritance hierarchy after three generations. No further subclasses of MyDate can be used.
As we hinted in the example, it may help to read ? super MyDate as "Assignable from MyDate." Lower bounds are useful for cases where we want to be sure that a particular container instantiation can hold a particular element type, without limiting it to just the specific type of the element. We'll show a good example of this when we talk about generic methods later. For now, just try to digest this as complementary to upper bounds.
One last thing about lower bounds: only the wildcard instantiation syntax can use the super keyword to refer to lower bounds. Bounds of type variables in generic class declarations cannot have lower bounds. Erasure replaces all references to the type variables with their upper bounds, so runtime types have no way to enforce the contract.