Что такое generics в Java и зачем нужен wildcard ? extends / ? super?
Дженерики — проверка типов на компиляции без приведений вручную. Wildcard: ? extends T — из коллекции читают как T (производитель), ? super T — в коллекцию пишут T (потребитель). Правило PECS: Producer Extends, Consumer Super.
- List<? extends Number> — можно получить Number, нельзя добавить Integer
- List<? super Integer> — можно добавить Integer, читать только как Object
- List<?> — только чтение как Object
А ещё Пример из JDK: Collections.copy(List<? super T> dest, List<? extends T> src)
Подробно
Зачем дженерики:
List names = new ArrayList(); // до Java 5
names.add(42); // компилятор молчит
String s = (String) names.get(0); // ClassCastException в рантайме
List<String> names = new ArrayList<>();
names.add(42); // ошибка компиляции
Почему нужны wildcard. Дженерики инвариантны: List<Integer> не подтип List<Number>. Метод sum(List<Number>) не примет список Integer. Решение — sum(List<? extends Number>).
? extends T — за ссылкой может быть List<Integer> или List<Double>. Читать как Number безопасно, а добавить нельзя ничего (кроме null): компилятор не знает, какой именно тип там.
? super T — за ссылкой List<Integer>, List<Number> или List<Object>. Добавить Integer безопасно, а прочитать можно лишь Object.
PECS — источник данных объявляют через extends, приёмник через super:
static <T> void copy(List<? super T> dest, List<? extends T> src)Что хотят услышать
- Зачем дженерики.
- Инвариантность и роль wildcard.
- PECS с примером.
Частые ошибки
- Пытаться добавлять элементы в ? extends.
- Ждать доступности T.class из-за стирания типов.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✓Проверка типов на компиляции; по PECS из ? extends T читают, в ? super T пишут
- ✗Дженерики проверяют типы во время выполнения
- ✗Проверка типов на компиляции; по PECS в ? extends T пишут, из ? super T читают
- ✗В List<? extends Number> можно добавить Integer
Что спросят дальше
- Что такое type erasure?
- Почему List<String> не является подтипом List<Object>?
Разбор темы
- Дженерики и стирание типов
Типобезопасность на компиляции, механизм type erasure и его последствия, дженерик-методы, ограниченные параметры и опасность raw types.
- Wildcards и правило PECS
Инвариантность дженериков против ковариантных массивов, ? extends/super, и когда что выбирать по PECS.
Связанные вопросы
- Что дают дженерики при работе с коллекциями? Junior
- Что можно делать со списком, объявленным как List<? extends Number>? Middle
- Метод должен перекладывать элементы из источника в приёмник. Какая сигнатура правильна по правилу PECS? Middle
- Почему List<String> нельзя присвоить переменной типа List<Object>? Middle
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.