Двойной супер-подстановочный знак - PullRequest
2 голосов
/ 26 мая 2020

В этом коде у меня ошибка во второй строке, а первая успешно компилируется:

Comparator<? super Integer> a = (x, y) -> Integer.compare(x, y);
Comparator<? super Integer> b = a.thenComparing((x, y) -> Integer.compare(x, y));

Ошибка: "несовместимые типы: объект не может быть преобразован в int"

thenComparing имеет следующую подпись: thenComparing(Comparator<? super T> other), поэтому, как я понимаю, other в этом контексте станет чем-то вроде Comparator<? super super T> или Comparator<? super super Integer>.

Почему в моем примере это становится Comparator<Object>?

Это недостаток компилятора или он меня от чего-то защищает?

1 Ответ

4 голосов
/ 26 мая 2020

Вы определяете a как Comparator<? super Integer>, и ваше присвоение (x, y) -> Integer.compare(x, y) его выполняет.

Однако компилятор не знает, какой именно тип ?. Это может быть Object, Number или Integer, но какой неизвестен. thenComparing() полагается на аргумент типа a, поскольку его подпись - Comparator<T> thenComparing(Comparator<? super T>). Вы передаете Comparator<Integer>, но аргумент типа a не совпадает.

Универсальные шаблоны неизменны . Comparator<? super Integer> не Comparator<Integer>. Используйте подстановочный знак, только если вам не нужен тип. В противном случае используйте аргумент правильного типа.

Определите a как Comparator<Integer>, чтобы исправить это.


Вот отличный ответ на другой пост Stackoverflow, объясняющий почему дженерики не являются неявно полиморфными c. Это также объясняет, в чем была бы проблема, если бы были дженерики.

...