Почему SomeClass <? super T> не эквивалентно SomeClass <T>в универсальных типах Java? - PullRequest
8 голосов
/ 30 октября 2008

Я заметил спецификацию для Collections.sort:

public static <T> void sort(List<T> list, Comparator<? super T> c)

Почему здесь необходимо "? super"? Если ClassB расширяет ClassA, то разве мы не можем гарантировать, что Comparator<ClassA> сможет сравнить два ClassB объекта в любом случае без части "? super"?

Другими словами, учитывая этот код:

List<ClassB> list = . . . ;
Comparator<ClassA> comp = . . . ;
Collections.sort(list, comp);

почему компилятор не настолько умен, чтобы знать, что это нормально, даже без указания "? super" для объявления Collections.sort ()?

Ответы [ 5 ]

7 голосов
/ 30 октября 2008

В этом году Джош Блох выступил с речью в Google I / O под названием Effective Java Reloaded , что может показаться вам интересным. В нем говорится о мнемонике под названием «Pecs» (производитель extends, потребитель super), которая объясняет, почему вы используете ? extends T и ? super T в своих входных параметрах (только; никогда не для возвращаемых типов) и когда использовать который.

6 голосов
/ 30 октября 2008

Это действительно хорошее (но извращенное) объяснение этого в Больше развлечений с подстановочными знаками .

1 голос
/ 30 октября 2008

Это похоже на C #, я только что узнал об этом пару дней назад о том, почему (трудный путь, а затем информативный способ PDC).

Предположим, Dog extends Animal

Blah<Dog> - это , а не , то же самое, что и Blah<Animal>, они имеют совершенно разные сигнатуры типов, хотя Dog расширяет Animal.

Например, предположим, что метод Blah<T>:

T Clone();  

В Blah<Dog> это Dog Clone();, а в Blah<Animal> это Animal Clone();.

Вам нужен способ отличить то, что компилятор может сказать, что Blah<Dog> имеет тот же открытый интерфейс, что и Blah<Animal>, и это то, что указывает <? super T> - любой класс, используемый как T, может быть приведен к своему суперклассу с точки зрения Blah<? super T>.

(в C # 4.0 это будет Blah<out T>, я полагаю.)

0 голосов
/ 30 октября 2008

Простой ответ на ваш вопрос заключается в том, что разработчик библиотеки хотел предоставить максимальную гибкость пользователю библиотеки; подпись этого метода, например, позволяет сделать что-то вроде этого:

List<Integer> ints = Arrays.asList(1,2,3);
Comparator<Number> numberComparator = ...;

Collections.sort(ints, numberComparator);

Использование подстановочного знака не позволяет вам использовать Comparator<Integer>; тот факт, что язык требует, чтобы разработчик библиотеки указывал подстановочный знак, позволяет ему или ей разрешать или ограничивать такое использование.

0 голосов
/ 30 октября 2008

Для вас очевидно, что в случае Comparator сработает любой предок T. Но компилятор не знает, что класс Comparator функционирует подобным образом - ему просто нужно сказать, должен ли он разрешать <T> или <? super T>.

С другой стороны, да, это правда, что любой Comparator предка будет работать в этом случае - и то, как разработчик библиотеки говорит, что это использовать <? super T>.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...