На этом шаге мы поговорим про подстановочные типы
Исследователям систем типов уже давно известно, что жесткие системы обобщенных типов использовать довольно неприятно. Поэтому создатели 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. В этом и состоит главный смысл ограниченных подстановок.
На следующем шаге мы рассмотрим ограничение супертипа на подставновки