Шаг 69.
Язык программирования Java.
Подстановочные типы

На этом шаге мы поговорим про подстановочные типы

Исследователям систем типов уже давно известно, что жесткие системы обобщенных типов использовать довольно неприятно. Поэтому создатели Java придумали изящный и в то же время не менее безопасный выход из положения: подстановочные типы. Рассмотрим пример:

Pair<? extends Employee>

Этот подстановочный тип означает любой обобщенный тип Pair, параметр типа которого обозначает подкласс, производный от класса Employee, в частности класс Pair<Manager>, но не класс Pair<String>.

Допустим, требуется написать следующий метод, который выводит пары сотрудников:

public static void printBuddies(Pair<Employee> p) {
        Employee first = p.getFirst();
        Employee second = p.getSecond();

        System.out.println(first.getName() + " and " +
        second.getName() + "are buddies.");
}

Как было сказано ранее, передать объект типа Pair<Manager> этому методу нельзя, что не совсем удобно. Но из этого положения имеется простой выход - использовать подстановочный тип следующим образом:

public static void printBuddies(Pair<? extends Employee> p) {...}

То есть тип Pair<Manager> является подтипом Pair<? extends Employee>. Заметим, что подстановки не могут нарушить тип Pair<Manager> по ссылке Pair<? extends Employee>. Рассмотрим следующий пример:

Pair<Manager> managerBuddies = new Pair<>(ceo, cfo);
Pair<? extends Employee> wildcardBuddies = new managerBuddies;
wildcardBuddies.setFirst(lowlyEmployee);

При вызове метода setFirst() произойдет ошибка соблюдения типов. Чтобы стала причина этой ошибки, рассмотрим поподробней обобщенный класс типа Pair<? extends Employee>. У него имеются следующие методы:

? extends Employee getFirst()
void setFirst(? extends Employee)

Причина в методе setFirst(). Компилятору требуется какой-нибудь подтип Employee, но неизвестно, какой именно. Он отказывается передать любой конкретный тип, поскольку знак подстановки ? может и не совпасть с этим типом. При вызове метода getFirst() такого затруднения не возникает. Значение, возвращаемое методом getFirst(), вполне допустимо присвоить переменной ссылки на объект типа Employee. В этом и состоит главный смысл ограниченных подстановок.

На следующем шаге мы рассмотрим ограничение супертипа на подставновки

Предыдущий шаг Содержание Следующий шаг