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