Возможно, вы знаете, что предикаты совместимы, а компилятор - нет.
Представьте себе этот пример:
Predicate<? extends Collection<Object>> p1 = (Set<Object> s) -> s.isEmpty();
Predicate<? extends Collection<Object>> p2 = (List<Object> l) -> l.get(0) != null;
Мы, разработчики, видим, что первый предикат может технически обрабатывать все коллекции, а второй - только списки. Но представьте, что предикаты были инициализированы где-то еще или будут изменены тем временем. Компилятор не может точно знать, для какого типа коллекций были созданы объекты предикатов. В результате вы не можете использовать их вообще:
Set<Object> set = new HashSet<>();
List<Object> list = new ArrayList<>();
p1.test(set);
p2.test(list);
p1.test(list);
p2.test(set);
Все эти вызовы не будут компилироваться, потому что компилятор не может сказать, могут ли фактические объекты, стоящие за p1
и p2
, именно для этих типов коллекций. В этом смысл ? extends Collection<>
: вы знаете, что это определенный подтип, но вы не можете сказать компилятору, какой именно.
Чтобы проиллюстрировать это на более простом примере:
Collection<Apple> appleBasket = ...;
appleBasket.add(new Apple()); // works
appleBasket.add(new Orange()); // does not work (obviously)
Collection<Fruit> mixedFruitBasket = ...;
mixedFruitBasket.add(new Apple()); // works
mixedFruitBasket.add(new Orange()); // works
// Now the tricky part
Collection<? extends Fruit> unknownButPureFruitBasket = ...;
unknownButPureFruitBasket.add(new Apple()); // does not work
unknownButPureFruitBasket.add(new Orange()); // does not work
Вы не можете добавить в корзину ни одного фрукта, тип которого вы не знаете. На самом деле это может быть корзина, в которую можно положить все фрукты, но это может быть корзина с чистыми яблоками, апельсиновым соусом или даже банановая корзина, о которой вы даже не знаете.
Попробуйте в вашей IDE:
List<? extends String> l1 = new ArrayList<>();
List<? extends String> l2 = new ArrayList<>();
l1.addAll(l2);
Затмение говорит мне:
Метод addAll (Collection1-of? Extends String>) в типе List 1 -of? extends String> не применим для аргументов (List 2 -of? extends String>)
Обратите внимание на различные типы: addAll
ожидает коллекцию capture#1
, l2
- коллекцию capture#2
.