These concepts are best understood through examples:
- Covariance: A
List<Integer>
can be assigned to a variable of typeList<? extends Number>
(as if it were a subtype ofList<Number>
). - Contravariance: A
Comparator<Object>
can be passed as a parameter to a methodList<Number>#sort
that expects aComparator<? super Number>
, as if it were a supertype ofComparator<Number>
.
There's also a related concept called invariance, which is the absence of covariance and contravariance properties. Generics without wildcards are invariant:
List<Number>
cannot be assigned to a variable of type List<Double>
or List<Object>
.Arrays in Java are covariant: a
String[]
value can be assigned to a variable of type Object[]
.Since Java 5, method overriding is covariant with respect to the return type and the types of exceptions.