Имеют ли дженерики в Java ограничения extends или implements
Что проверяют
Знаете ли вы синтаксис ограничений типов и понимаете ли, почему он такой. Вопрос с подвохом: implements в объявлении дженерика не существует. Следом обычно идут wildcard-типы, PECS и стирание типов.
Как отвечать
Сразу ответьте на ловушку: у параметра типа есть только extends, и он означает «является подтипом» и для классов, и для интерфейсов. class Sorter<T implements Comparable<T>> не скомпилируется, правильно class Sorter<T extends Comparable<T>>.
Дальше покажите, что знаете детали:
- верхняя граница:
<T extends Number>позволяет вызывать уTметодыNumber, напримерdoubleValue(); - несколько границ:
<T extends Number & Comparable<T>>. Класс может быть только один и идёт первым, дальше любое число интерфейсов через&; - рекурсивная граница:
<T extends Comparable<? super T>>, так объявленCollections.sort(). Сюда жеEnum<E extends Enum<E>>; - нижняя граница:
superбывает только у wildcard, напримерList<? super Integer>. Параметр типа вида<T super X>не разрешён; - wildcard и PECS:
? extends Tдля источника, из него читают,? super Tдля приёмника, в него пишут. Отсюда сигнатураCollections.copy(List<? super T> dest, List<? extends T> src).
Добавьте про стирание: в байткоде T заменяется своей первой границей. Для <T extends Number & Comparable<T>> это Number, поэтому порядок границ влияет на сигнатуру после компиляции. Классический пример Collections.max(): там объявлено <T extends Object & Comparable<? super T>>, чтобы после стирания метод возвращал Object, как до появления дженериков, и старый байткод не сломался.
Где спотыкаются
Пишут implements по аналогии с объявлением класса и уверенно рассказывают про «ограничение интерфейсом через implements».
Считают List<Integer> подтипом List<Number>. Дженерики инвариантны, для гибкости как раз и нужны wildcard-типы.
Пытаются добавить элемент в List<? extends Number>. Компилятор не даст: он не знает конкретный тип списка, туда можно положить только null.