Легче всего осознать эти понятия на примерах:
- Ковариантность:
List<Integer>
можно присвоить в переменную типаList<? extends Number>
(как будто он наследникList<Number>
). - Контравариантность: в качестве параметра метода
List<Number>#sort
типаComparator<? super Number>
может быть переданComparator<Object>
(как будто он родительComparator<Number>
).
Существует еще одно связанное понятие – инвариантность. Инвариантность – это отсутствие свойств ковариантности и контрвариантности. Дженерики без вайлдкардов инвариантны:
List<Number>
нельзя положить ни в переменную типа List<Double>
, ни в List<Object>
.Массивы ковариантны: в переменную
Object[]
можно присвоить значение типа String[]
.Переопределение методов начиная с Java 5 ковариантно относительно типа результата и типов исключений.