Generics

Вопросы к собеседованию

Вопросы:

Generics

Generics - набор свойств языка позволяющих определять и использовать обобщенные типы и методы.

Обобщенные типы или методы отличаются от обычных тем, что имеют типизированные параметры (T – параметр в котором могут быть разные объекты).

ArrayList<Integer> list = new ArrayList<Integer>();

Свойства Generics:

Ограничения:

Примером использования обобщенных типов может служить Java Collection Framework.

Так, класс LinkedList<E> - типичный обобщенный тип. Он содержит параметр E, который представляет тип элементов, которые будут храниться в коллекции.

Создание объектов обобщенных типов происходит посредством замены параметризированных типов реальными типами данных.

Вместо того, чтобы просто использовать LinkedList, ничего не говоря о типе элемента в списке, предлагается использовать точное указание типа LinkedList<String>, LinkedList<Integer> и т.п.

Для чего нужны дженерики?

Generics (обобщенные типы и методы) позволяют нам уйти от жесткого определения используемых типов.

С их помощью можно объявлять классы, интерфейсы и методы, где тип данных указан в виде параметра.

Возможность создавать универсальные алгоритмы и структуры данных.

Позволяет осуществлять проверку на правильность написания кода во время компиляции, а не в Runtime.

Компилятор стирает все дженерики. В Runtime дженериков практически нет. Компилятор использует кастование.

Хоть бы слово про стирание типов...

Сделали использование Java Collection Framework проще, удобнее и безопаснее.

Стирание типов

Это когда при компиляции из обобщенных классов с параметрами генерируется код обычных сырых классов с расстановкой, где нужно, приведения типов, генерацией дополнительных методов и т.д.

Дженерики существуют только на этапе компиляции и только для компилятора.

Стираются вверх (т.е. если не указано extends, то стирается в Object)

очень классный видосик

Что такое сырые типы (raw type)?

Raw type - это имя интерфейса без указания параметризованного типа

Сырые типы — это типы без указания "уточненения" в фигурных скобках.

Нужны чтобы поддерживать старый код (обратная совместимость).

Рекомендуется использовать хоть какие-то параметризованные типы.

Также Diamond синтаксис связан с понятием "Type Inference", или же выведение типов. Ведь компилятор, видя справа <> смотрит на левую часть, где расположено объявление типа переменной, в которую присваивается значение. И по этой части понимает, каким типом типизируется значение справа.

List <String> list = new ArrayList<>();

На самом деле, если в левой части указан дженерик, а справа не указан <>, компилятор сможет вывести тип. Однако это будет смешиванием нового стиля с дженериками и старого стиля без них - вы теряете безопасность (типобезопасность) типов (может добавляться какой угодно тип в список, а не то что надо. Когда будет доставаться – то может быть сюрприз)))

ArrayList <String> strings = new ArrayList<>(); // parameterized type

ArrayList arrayList = new ArrayList(); // raw type

arrayList = strings; // Ok

strings = arrayList; // Unchecked assignment (назначение)

arrayList.add(1); //unchecked call

Что такое вайлдкарды (Маски)

Языковая конструкция внутри diamond-оператора, позволяющая сделать код более универсальным.

Решает проблему наследования типов в дженериках.

Может быть 3-х типов: инвариантность, upper и lower.

Принцип PECS

The Get and Put Principle или PECS (Producer Extends Consumer Super) Get and Put Principe

Из одного типа переменных можно только читать, в другой — только вписывать (исключением является возможность записать null для extends и прочитать Object для super).

Если метод имеет аргументы с параметризованным типом (например, Collection или Predicate), то в случае, если аргумент - производитель (producer), нужно использовать ? extends T, а если аргумент - потребитель (consumer), нужно использовать ? super T.

Eсли метод читает данные из аргумента, то этот аргумент - производитель, Метод передаёт данные в аргумент, то аргумент является потребителем. Важно заметить, что определяя производителя или потребителя, мы рассматриваем только данные типа T.

Если ни хрена не поняли - смотрите видосик

Тип Что можно присвоить = Что можно читать get() Что можно добавлять add()
Инвариантный
List<Type>
Только List<Type> Type и предки Type Type и наследники Type
Ковариантный
List<? extends Type>
List<Type> и List наследников Type Type и предки Type Ничего
Контрвариантный
List<? super Type>
List<Type> и List предков Type Object Type и наследники Type