В Java ковариация позволяет дизайнеру API указывать, что экземпляр может быть обобщен как определенный тип или любой из подтипов этого типа. Например:
List<? extends Shape> shapes = new ArrayList<Circle>();
// where type Circle extends Shape
Контравариантность идет в другую сторону. Это позволяет нам указать, что экземпляр может быть обобщен как определенный тип или супертип.
List<? super Shape> shapes = new ArrayList<Geometry>();
// where Shape extends Geometry
Как применима общая контравариантность Java? Когда вы решите использовать его?