Java: Дженерики
Теория: Как работают дженерики
Тип данных определяет набор операций, который допустим для данного типа. Например, мы можем складывать числа, но не можем складывать булевы значения.
Однако, логика кода не всегда зависит от того, с каким типом данных происходит работа. Ярким примером служат коллекции, где большая часть операций никак не связана с типом данных, который находится внутри. Например, операция добавления элемента в список никак не затрагивает сам элемент. То же самое касается изменения, удаления и большей части остальных операций. Эти операции производятся над самой коллекцией, но сами элементы никак не обрабатываются.
Представьте если бы коллекций в том виде, в котором мы с ними знакомились в Java не существовало. Как бы мы их реализовали? У нас было бы два способа:
Создать свой вариант коллекции для каждого типа данных
Ровно такой же класс мы сделаем и для остальных типов. Разница в этих классах будет исключительно в типе данных, который указан в описании класса:
Представьте, что, то же самое придется делать для каждого нового класса или интерфейса, которые добавляются в код. Никто не захочет тратить на это время. Поэтому обычно идут другим способом.
Приведение к Object
В Java все классы неявно наследуют класс Object. Тему наследования мы еще не проходили, но для данной задачи нам не нужны глубокие знания. Достаточно увидеть, что любой объект можно привести к типу Object, а можно выполнить обратное преобразование.
Таким образом мы можем создать ровно один класс, хранящий в себе все данные в виде Object.
Использование:
У этого способа есть серьезный недостаток, это необходимость вручную следить за типами и как следствие, отсутствие типобезопасности. В такую коллекцию можно добавить любые данные, так как все типы в Java являются подтипами Object.
Все это привело к тому, что в языке появились дженерики, которые с одной стороны убирают дублирование кода, с другой обеспечивают типобезопасность. Концепция дженериков основана на понятии "параметр типа". То есть у типа (класса или интерфейса) появляется параметр, который тоже является типом. Этот параметр определяет то, с каким типом будет работать дженерик для конкретной ситуации, например, созданного объекта. Синтаксически, параметр типа указывается в угловых скобках во время создания объекта из дженерика.
Внутри это выглядит примерно так:
После названия класса ставятся угловые скобки, внутри которых используется имя для параметра типа. Обычно пишут T, но это не обязательно. Внутри класса параметр типа используется там, где бы использовался обычный тип. Единственное исключение в случае коллекций заключается в том, что данные все равно надо хранить как объекты. Преобразование делается во время получения данных, внутри дженерика.
Программирование с использованием дженериков часто называют обобщенным программированием, а сами дженерики параметризуемыми типами. Так как дженериками выступают классы и интерфейсы, в которые как в методы передается параметр, только в отличие от методов, параметром является не значение какого-то типа, а сам тип.



