В
объявлении дженерик-параметра класса или метода может быть указана его верхняя граница (bound):
class Foo<T extends Number>
Ключевое слово
extends
применяется как для классов, так и для интерфейсов. Фактическим параметром такого класса
Foo
может быть или сам
Number
, или его наследники.
Помимо ограничения возможных применяемых типов, bounded-параметр дает право использовать в реализации методы и поля типа-ограничителя – он будет как минимум предком фактического типа. Это достигается
стиранием типа-параметра до верхней границы.
Тип-параметр может иметь несколько верхних границ, то есть границу-пересечение типов:
<T extends Comparable & Serializable>
. Стирание произойдет до первой из границ, остальные послужат только ограничением вариантов фактического типа. Поэтому граница-класс, при наличии, должна быть указана раньше границ-интерфейсов.
При указании
значения дженерик-параметра переменной может быть использован
вайлдкард – символ
?
. Вайлдкард значит, что мы не собираемся использовать информацию о конкретном типе, этот тип может быть любым. Это
не то же самое, что не указать дженерик параметр совсем.
Для вайлдкарда также как и для объявления типа-параметра можно обозначить верхнюю границу. Но в отличие от объявления, здесь нельзя использовать пересечение типов, по крайней мере
пока.
Кроме того, в случае вайлдкарда можно задать нижнюю границу:
Foo<? super Number> foo;
Означает, что мы не будем использовать информацию о конкретном типе, но будем знать что это предок класса
Number
. То есть или сам
Number
, или
Object
.
В объявлении класса или метода использование
super
запрещено, так как
не имеет смысла.
Лучше разобраться в механике использования ограниченных вайлдкардов поможет
это видео.
Хороший API должен уметь эффективно работать с классами-наследниками, то есть быть ко- или контравариантным где это необходимо. При этом без bounded вайлдкардов не обойтись. Чтобы запомнить, какая граница нужна в каких случаях, Joshua Bloch предложил мнемонику
PECS:
Producer-extends, Consumer-super.