In the
declaration of a generic parameter for a class or method, you can specify an upper bound:
class Foo<T extends Number>
The keyword
extends
is used for both classes and interfaces. The actual parameter for such a class
Foo
can be either
Number
itself or its subclasses.
Apart from restricting the possible types that can be used, a bounded parameter allows you to use methods and fields of the bound type in the implementation—since it will be at least a superclass of the actual type. This is achieved through
type erasure to the upper bound.
A type parameter can have multiple upper bounds, forming a type intersection:
<T extends Comparable & Serializable>
. Erasure will occur to the first bound, and the others will only serve to restrict the actual type. Therefore, a class bound, if present, must be listed before interface bounds.
When specifying a generic parameter
value for a variable, you can use a
wildcard ?
. A wildcard means that you are not going to use information about the specific type - it can be any type. This is
different from not specifying a generic parameter at all.
For wildcards, you can also specify an upper bound, just like when declaring a type parameter. However, unlike declarations, wildcards cannot use type intersections - at least
not currently.
Additionally, in the case of wildcards, you can specify a lower bound:
Foo<? super Number> foo;
This means that you won't use information about the specific type, but you will know that it is a superclass of
Number
- either
Number
itself or
Object
.
In class or method declarations, using
super
is prohibited because it
doesn't make sense.
A good API should efficiently handle subclasses, meaning it should be co- or contravariant where necessary. In such cases, bounded wildcards are essential. To remember which bound is needed in different scenarios, Joshua Bloch proposed the mnemonic
PECS:
Producer-extends, Consumer-super.