-
Notifications
You must be signed in to change notification settings - Fork 3
Generics
Зачем нужны Generics? //todo
-
Инвариантность
Это когда можно подставлять только определенный тип.
-
Ковариантность
Это когда можно подставлять более конкретный тип, вместо более обобщенного.
Это у нас
extends
. -
Контрвариантность
Это когда можно подставлять более общий тип, вместо более конкретного.
Это у нас
super
.
####А теперь подробнее:
List в Java инвариантен, т.е если у меня есть два класса, один из которых наследник другого, например, List и List, то эти коллекции - не являются наследниками друг друга и подставить одну вместо другой мы не можем. Они инвариантны.
List<String> strings = new ArrayList<>();
List<Object> objects = strings; //wrong!
Так делать запрещено! Почему? Потому что если бы такое было разрешено, то мы бы получали ошибки в рантайме, которые сложно отследить. Когда я бы у коллекции objects какой-нибудь элемент кастовал бы в String, а он был бы не String.
Чтобы это работало - надо использовать ограничения. Так как у нас тут list - это producer данных, то использовать надо extends. //todo example
Есть еще ограничения super. Если у нас коллекция - это Consumer. Коллекция потребляет данные, т.е мы туда что-то записываем. Тогда можно написать так:
static void putAnimalToCollection(List<? super Animal> list) {
list.add(new Cat("Kitty"));
list.add(new Dog("Doggerman"));
}
Мы можем только писать туда, но не забирать оттуда данные, так как мы не знаем, что конкретно к нам придет из такой коллекции. Т.е компилятор считает, что там Object, поэтому мы не знаем к чему кастовать.
Это еще называется PECS
- Producer extends Consumer super.
Еще раз: Producer - может работать с типом T и его наследниками, Consumer - может принимать T и его предков.