Расскажите, что такое дженерики в Java и в чём различия между инвариантностью, ковариантностью и контравариантностью при их использовании?
Ответ от нейросети
sobes.tech AI
Дженерики в Java позволяют создавать классы, интерфейсы и методы с параметрами типов, что обеспечивает типобезопасность и переиспользуемость кода без необходимости кастов.
Инвариантность означает, что параметр типа должен точно совпадать. Например, List<String> не является подтипом List<Object>.
Ковариантность позволяет использовать более конкретный тип, чем ожидается. В Java это реализуется через wildcard с extends: List<? extends Number> — можно читать элементы как Number, но нельзя добавлять.
Контравариантность — наоборот, позволяет использовать более общий тип. В Java это wildcard с super: List<? super Integer> — можно добавлять Integer и его подтипы, но при чтении получаем Object.
Пример:
List<? extends Number> numsCovariant = new ArrayList<Integer>();
Number n = numsCovariant.get(0); // чтение разрешено
// numsCovariant.add(10); // ошибка компиляции
List<? super Integer> numsContravariant = new ArrayList<Number>();
numsContravariant.add(10); // добавление разрешено
Object obj = numsContravariant.get(0); // чтение возвращает Object
Таким образом, ковариантность удобна для чтения, контравариантность — для записи.