Подтвердить что ты не робот

Объявление Collections.sort(): почему <? супер T>, а не <T>

Почему Collections.sort(List<T>) имеет подпись:

public static <T extends Comparable<? super T>> void sort(List<T> list) 

и не:

public static <T extends Comparable<T>> void sort(List<? extends T> list)
  • Я понимаю, что оба они будут выполнять одну и ту же цель; так почему разработчики фреймворка использовали первый вариант?
  • Или эти объявления действительно разные?
4b9b3361

Ответ 1

Ваша предлагаемая подпись, вероятно, будет работать на Java-8. Однако в предыдущих версиях Java тип вывода не был настолько умным. Подумайте, что у вас есть List<java.sql.Date>. Заметим, что java.sql.Date расширяет java.util.Date, который реализует Comparable<java.util.Date>. Когда вы компилируете

List<java.sql.Date> list = new ArrayList<>();
Collections.sort(list);

Он отлично работает в Java-7. Здесь T выведено как java.sql.Date, которое на самом деле Comparable<java.util.Date>, которое Comparable<? super java.sql.Date>. Однако попробуйте свою подпись:

public static <T extends Comparable<T>> void sort(List<? extends T> list) {}

List<java.sql.Date> list = new ArrayList<>();
sort(list);

Здесь T следует вывести как java.util.Date. Однако спецификация Java 7 не допускает такого вывода. Следовательно, этот код можно скомпилировать с помощью Java-8, но сбой при компиляции под Java-7:

Main.java:14: error: method sort in class Main cannot be applied to given types;
        sort(list);
        ^
  required: List<? extends T>
  found: List<Date>
  reason: inferred type does not conform to declared bound(s)
    inferred: Date
    bound(s): Comparable<Date>
  where T is a type-variable:
    T extends Comparable<T> declared in method <T>sort(List<? extends T>)
1 error

В Java-8 значительно улучшился вывод типа. Отдельная JLS глава 18 посвящена ему сейчас, а в Java-7 - правила были намного проще.

Ответ 2

// 0
public static <T extends Comparable<? super T>> void sort0(List<T> list) 

// 1
public static <T extends Comparable<T>> void sort1(List<? extends T> list)

Эти подписи различаются, потому что они накладывают разные требования на отношение между типом T и аргументом типа Comparable в определении T.

Предположим, например, что у вас есть этот класс:

class A implements Comparable<Object> { ... }

Тогда, если у вас есть

List<A> list = ... ;
sort0(list); // works
sort1(list); // fails

Причина sort1 не соответствует тому, что существует тип no T, который сопоставим с самим собой и является или является супертипом типа списка.

Оказывается, что класс A неверен, потому что объекты, которые Comparable, должны соответствовать определенным требованиям. В частности, обратное сравнение должно обратить вспять знак результата. Мы можем сравнить экземпляр A с Object, но не наоборот, поэтому это требование нарушено. Но учтите, что это требование семантики Comparable и не налагается системой типов. Учитывая только систему типов, две объявления sort действительно различны.

Ответ 3

Они различаются, потому что ? super T менее ограничительный, чем T. Это нижний ограничиваемый подстановочный знак (частично связанное учебное пособие по Java)

Термин List<Integer> более ограничительный, чем List<? super Integer>, потому что первый соответствует только списку типов Integer, тогда как последний соответствует списку любого типа, который является супертипом Integer.

Замените Integer на T, а это означает T или a java.lang.Object.