Core-2: Jenerics Flashcards
Коваринтность, Контрваринтность, Инваринтность
Вариантность — перенос наследования исходных типов на производные от них типы. Под производными типами понимаются контейнеры, делегаты, обобщения, а не типы, связанные отношениями “предок-потомок”. Различными видами вариантности являются ковариантность, контравариантность и инвариантность.
Ковариантность — перенос наследования исходных типов на производные от них типы в прямом порядке.
Контравариантность — перенос наследования исходных типов на производные от них типы в обратном порядке.
Инвариантность — ситуация, когда наследование исходных типов не переносится на производные.
Что такое Дженерики?
Дженерики (или обобщения) - это параметризованные типы.
Параметризованные типы позволяют объявлять классы, интерфейсы и методы, где тип данных, которыми они оперируют, указан в виде параметра.
Дженерики –cвойства языка, позволяющие типизировать классы и методы.
Типизировать - явно указывать типы объектов, с которыми может работать данный метод, класс или содержать данная структура данных.
- Появились в версии 1.5
Для чего нужны дженерики? (2)
- Для строгой типизации и проверки на этапе компиляции:
Дженерики позволяют передавать тип объекта компилятору в формате<тип>
. Таким образом, компилятор может выполнить все необходимые действия по проверке типов во время компиляции, обеспечивая безопасность по стиранию и приведению типов во время выполнения:
Информация о типах доступна только на этапе компиляции и стирается в runtime, и в байт код попадет только информация о том, что в программе есть некий список List list вместо List<String> list, например.</String> - Для универсификации кода: Используя дженерики, можно создать единственный метод или класс, который будет автоматически работать с разными типами данных.
Что такое сырые типы (raw type)?
“Сырые типы — это дженерик класс или интерфейс без спецификации типа :
~~~
List list = new ArrayList();
class User<T>{} => { User user = new User; }
~~~
они использовались до появления дженериков.
Не указывая их, под капотом используется Object</T>
Какие есть ограничения на использование Дженериков? (6)
1) работают только со ссылочными типами
2) Они инвариантны - наследование ограничено:
~~~
if (Foo extends Bar) ->
List<Foo> !extends List<Bar>
~~~
3) типизированный Т объект нельзя объявить через new: `Box<T> genericBox = new Box<T>();` - так нельзя
4) неприменимы к массивам, так как массивы ковариантны.
5) в обобщенном Т классе статические поля не могут быть static T, методы не могут возвращать Т. Зато стат. методы могут иметь параметры дженерики, причем этот метод необходимо дополнительно типизирвать (`public class C <T> { static <T> Object act( T е) { return new Object();}}`)
6) Типизированные классы не могут наследоваться от Throwable.</T></T></T></T></Bar></Foo>
Что означает конструкция public class Main <T extends Number>
?
Что класс работает с Number и наследниками, что дает возможность вызывать методы Number на T объекты. Такой возможности не было бы в случае class Main <T>
Что такое wildcard и какую проблему решает?
Языковая конструкция внутри даймонд-оператора.
Решает проблему наследования типов в дженериках. (коллекция <Интежер> не наследник коллекции <Намбер>)
Можем ли мы использовать ? для типизации параметра метода? (public static <?> void print(? item)
)
Нет, <?>
может только параметризовать объекты, надо делать так:public static <T> void print(T item)
Какое написание предпочтительнее: public static <E> void swap(List<E> list, int src, int des);
VS
public static void swap(List<?> list, int src, int des);
2е, так как если мы имеем неограниченный дженирик тип ( если подойдет вообще любая коллекция) - то следует использовать <?>
Так же если дженерик присутствует в объявлении метода лишь однажды, нам следуеет выбрать вайлдкард, даже если имеется верхнее или нижнее ограничиние.
Можем ли мы обратиться к методу public static <E> List<? extends Number> mergeWildcard(List<? extends E> listOne, List<? extends E> listTwo)
таким образом: List<Number> numbersMerged = .mergeWildcard(numbers1, numbers2);
?
Он не скомпилируется, так какList<Number> != List<? extends Number>
, ведь метод имеет право вернуть любой конкретный лист (<Integer>, <Double>, ...
).
Если мы изменим возвращаемое значение на List<E>
, то всё будет работать, так как теперь мы гарантируем, что у метода на входе и на выходе будут листы одного типа.
Таким образом, если метод возвращает дженеризированный объект, следует использовать типизированный дженерик, а не вайлдкард.
NB: Данный метод сработает если:List list = ... ; / List<? extends Number> = ...;
,
и потом мы сможем попытаться извлечь из него Number:
~~~
Number n = (Number) numbersMergeds.get(0);
~~~
Что означает тип List<? extends Number>
в аргументе метода?
Что придет коллекция, содержащая Number или наследников.
Что означает тип List<? Super Integer>
в аргументе метода?
Что придет коллекция, содержащая Integer или его предков.
Как понять List<?>
?
List<?> ==
List<? extend Object>
what is the difference between List<?> and List<T> in java?
- ? означает вообще любой тип и при чтении из этого листа возвращается Object
- из ? мы можем только читать, с Т можем делать всё.
объяснить public User<?> getUser()
метод возвращает юзера с неизвестным параметром. может использоваться когда тип не важен или он будет определяться в рантайме (например при доставании юзера из базы).