Дженерики. JAVA Flashcards
Что такое Дженерики? (7)
Позволяют создавать обобщенные типы данных, работающие с различными типами объектов.
С помощью дженерика мы указываем: “тут будет переменная какого-то типа, неважно какого, главное, чтобы имела такие-то свойства”.
Дженерики позволяют создавать Параметризированные классы и методы, в которых тип данных указан в виде параметра, и которые могут работать с любыми типами данных.
А конкретный тип данных подставляется уже во время использования класса, как параметр, что делает код более гибким и универсальным.
Дженерики используют параметризованные типы (parameterized types), которые определяются с помощью угловых скобок < >.
Например, класс ArrayList может быть параметризован типом элементов, которые он будет содержать.
Эта информация доступна только на этапе компиляции и стирается в runtime, и в байт код попадет только информация о том, что в программе есть некий список List<object> list вместо List<String> list, например.</String></object>
Дженерики используют только ссылочные типы данных
Появились в версии 1.5
Для чего нужны дженерики?(4)
Для строгой типизации и проверки на этапе компиляции.
Дженерики позволяют передавать тип объекта компилятору в форме <тип>. Таким образом, компилятор может выполнить все необходимые действия по проверке типов во время компиляции, обеспечивая безопасность по приведению типов во время выполнения.</тип>
С помощью дженериков мы можем писать классы и методы, которые не привязаны только к одному типу. Тип данных указываются в качестве параметров, которые должны быть ссылочным типом.
Возможность создавать универсальные алгоритмы и структуры данных, т.е. используя Дженерики, можно создать единственный метод или класс, который будет автоматически работать с разными типами данных.
Что такое сырые типы (raw type)?
Сырые типы (raw type) - это НЕ типизированные версии классов и интерфейсов, которые используются в Java до версии 5.0, когда появились дженерики.
Например:List list = new ArrayList<>(),
Суть Raw Types заключается в том, что внутри класса не хранится никакой информации о типе-параметре. Эта информация доступна только на этапе компиляции и стирается (становится недоступной) в runtime.
Что такое Type Erasure?
Стирание типов - удаление информации о заданных с помощью дженериков классах, и преобразование их в Raw Types
Происходит на этапе компиляции.
—– Тип параметра <T> преобразуется в Object
----- Тип параметра <T> в Comparable
----- Запись вида List<String> преобразуется в List и т.д.</String></T></T>
Стирание типов возникло для поддержки обратной совместимости.
Виртуальная машина не умеет работать с дженериками изначально, поэтому их требуется убирать после компиляции.
Не рекомендуется использовать RAW TYPES
Что такое wildcard и какую проблему решает?
Средство языка для указания границ входных значений.
Wildcard позволяет определить параметризованный тип без указания конкретного типа данных.
Может быть 3-х типов: инвариантность, аппер и ловер:
- Неограниченный
wildcard (?)
-тип данных не ограничен и может быть любым;List<?> list = new ArrayList<>(); // неограниченный wildcard
- Ограниченный
wildcard (? extends)
- ограничивает тип данных сверху, он должен быть наследником определенного класса или интерфейса;List<? extends Number> list = new ArrayList<>(); // ограниченный wildcard
- Супер-ограниченный
wildcard (? super)
- ограничивает тип данных снизу, он должен быть предком для определенного класса или интерфейса.List<? super Integer> list = new ArrayList<>(); // супер-ограниченный wildcard
- Wildcard позволяет создавать более гибкие и универсальные дженерики в Java
- Решает проблему наследования типов в дженериках. (коллекция
<Integer>
не наследник коллекции<Number>
)
Что такое PECS?
PECS - это аббревиатура, которая означает “Producer Extends Consumer Super”, и используется для указания правильного использования обобщенных типов в Java.
Откуда берем - extends, Куда кладем - super
Из одного типа переменных можно только читать, в другой — только вписывать
- Если wildcard с extends, то это producer. - означает, что дженерик используется только для чтения данных из коллекции (или другой структуры данных.;
- Метод Принимает на вход: Тип Т и Т-Потомки;
- Позволяет ЧИТАТЬ элементы из: Предки-Т и Тип Т;
- ПИСАТЬ НЕЛЬЗЯ - ТОЛЬКО null
- Если wildcard с super — то это consumer - означает, что дженерик используется только для записи данных в коллекцию (или другую структуру данных);
- Метод Принимает на вход: Предки-Т и Тип Т
- Позволяет ПИСАТЬ элементы из: Тип Т и Т-Потомки;
- ЧИТАТЬ НЕЛЬЗЯ - ТОЛЬКО Object
Иначе говоря:
Если вы только получаете объекты из дженерик-коллекции - это producer и надо использвовать extends.
Если вы только кладете объекты в коллекцию - это consumer и надо использовать super.
Если вы делаете оба эти действия, то не надо использовать ни super, ни extends.
Что такое Инвариантность?
Инвариантность — отсутствие наследования между производными типами. Если Кошка — это подтип Животные, то Множество<Кошки>
не является подтипом Множество<Животные>
и Множество<Животные>
не является подтипом Множество<Кошки>
.
«Дженерики» инвариантны.
Что такое Ковариантность?
Ковариантность в Java позволяет использовать объекты с более специфическим типом в контексте, где требуется более общий тип.
Если есть классы, которые наследуются друг от друга, то можно использовать объекты класса-наследника вместо объектов класса-предка, когда это нужно.
Множество<Животные> = Множество<Кошки>
Produser Extends - Ковариантность
Что такое Контрвариантность?
Контрвариантность в Java позволяет использовать объекты с более общим типом в контексте, где требуется более специфический тип.
Если есть классы, которые наследуются друг от друга, то можно использовать объекты класса-предка вместо объектов класса-наследника, когда это нужно.
Множество<Кошки> = Множество<Животные>
Consumer Super: Контрвариантность
Какие есть ограничения на использование Дженериков?(6)
1) принимают только ссылочный типы данных
2) Они инвариантны - наследование ограничено:
if (Foo extends Bar) -> List<Foo> НЕ extends List<Bar>
3) нельзя объявить через new: Box<T> genericBox = new Box<T>();
- так нельзя
4) неприменимы к массивам, так как массивы ковариантны.
5) статические члены класса: поля не могут быть static T
, методы тоже. Зато стат. методы могут иметь параметры дженерики
6) Типизированные классы не могут наследоваться от Throwable, но могут от RuntimeException или Exception.
Какие бывают типы дженериков?
1) Просто дженерик: <T>. При компиляции преобразуется в тип Object.
2) Дженерик, расширяющий класс или интерфейс: <T extends String, U extends Comparable>. При компиляции T преобразуется в тип String, U преобразуется в тип Comparable.
3) Параметр типа Wildcard - знак вопроса ("?"). Предназначен для определения не только одного класса, но и его подклассов в качестве допустимых (? extends String).</T>