Skip to content
Aleksandr Kuchuk edited this page Jul 27, 2016 · 10 revisions

Введение

Зачем нужны Generics? //todo

Generics

Wildcards

  • Инвариантность

    Это когда можно подставлять только определенный тип.

  • Ковариантность

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

    Это у нас 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 и его предков.

Clone this wiki locally