Что такое generics?
Generics - это технический термин, обозначающий набор свойств языка позволяющих определять и использовать обобщенные типы и методы. Обобщенные типы или методы отличаются от обычных тем, что имеют типизированные параметры.
Примером использования обобщенных типов может служить Java Collection Framework. Так, класс LinkedList<E> - типичный обобщенный тип. Он содержит параметр E, который представляет тип элементов, которые будут храниться в коллекции. Создание объектов обобщенных типов происходит посредством замены параметризированных типов реальными типами данных. Вместо того, чтобы просто использовать LinkedList, ничего не говоря о типе элемента в списке, предлагается использовать точное указание типа LinkedList<String>, LinkedList<Integer> и т.п.
Wildcards (подстановочные символы)
В generics используются подстановочные символы (wildcards):
?— неограниченный подстановочный тип (unbounded wildcard), напримерList<?>— список элементов неизвестного типа;? extends T— верхняя граница (upper bounded wildcard), означает «T или любой его подтип». Например,List<? extends Number>может содержатьInteger,Doubleи т.д.;? super T— нижняя граница (lower bounded wildcard), означает «T или любой его супертип». Например,List<? super Integer>допускаетInteger,Number,Object.
Принцип выбора между extends и super описывается правилом PECS (Producer Extends, Consumer Super): если параметризованный тип является источником данных (producer), используйте ? extends T; если потребителем данных (consumer) — ? super T.
Стирание типов (Type Erasure)
Информация о параметрах типов существует только на этапе компиляции. Во время выполнения (runtime) она стирается — это называется стирание типов (type erasure). Компилятор заменяет все параметры типов их границами или Object, если границы не указаны, и при необходимости вставляет приведения типов. Таким образом, List<String> и List<Integer> на уровне байт-кода являются одним и тем же типом List.
Обобщённые методы (Generic Methods)
Обобщённые методы позволяют параметризировать конкретный метод, а не весь класс:
Пример
public static <T extends Comparable<T>> T max(T a, T b) {
return a.compareTo(b) >= 0 ? a : b;
}
// Вызов:
String result = max("abc", "xyz"); // тип T выводится автоматически
Ограничения generics
- Нельзя использовать примитивные типы в качестве параметра типа (
List<int>— ошибка компиляции, следует использоватьList<Integer>); - Нельзя создавать экземпляры параметров типа (
new T()— ошибка компиляции); - Нельзя создавать массивы параметризованных типов (
new List<String>[10]— ошибка компиляции); - Из-за стирания типов нельзя использовать
instanceofс параметризованными типами (obj instanceof List<String>— ошибка компиляции, ноobj instanceof List<?>допустимо); - Нельзя создавать обобщённые исключения (класс, расширяющий
Throwable, не может быть параметризован).