Объяснение универсального <T расширяет Comparable <? супер T >> в collection.sort/ сравнимый код?

Я все время использую сопоставимый интерфейс, чтобы обеспечить естественное упорядочение для моего класса через collection.sort.

По сути, если у меня есть класс person, я получу его для реализации интерфейса Comparable и обеспечу реализацию CompareTo. Однако в определении Collections.sort в javadocs я вижу эту подпись

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

Я вообще не понимаю это определение дженериков? Разве это не должно просто сказать

<T implements Comparable<T>>

Может кто-то помочь мне с этим?

2 ответа

Решение

На самом деле, это означает, что T может реализовать Comparable<? super T>, не просто Comparable<T>,

Например, это означает, что Student класс может реализовать Comparable<Person>, где Student это подкласс Person:

public class Person {}

public class Student extends Person implements Comparable<Person> {
    @Override public int compareTo(Person that) {
        // ...
    }
}

В этом случае список может быть отсортирован по Collections.sort() но только на основе Personсвойства, потому что вы передаете Student экземпляр в compareTo() как Person (если, конечно, вы не опускаете руки).

Однако на практике вы никогда не увидите Student реализовать класс Comparable<Person>, Это потому что Person вероятно, реализовали Comparable<Person>, а также Student наследует это реализация. Однако конечный результат тот же: вы можете передать List<Student> в Collections.sort() и отсортировать по Personсвойства.

Разница между Comparable<T> а также Comparable<? super T> более очевидно в перегруженной версии Collections.sort(), которая принимает Comparator<? super T>:

class ByAgeAscending implements Comparator<Person> {
    @Override public int compare(Person a, Person b) {
        return a.getAge() < b.getAge();
    }
}

List<Student> students = getSomeStudents();
Collections.sort(students, new ByAgeAscending());

Вы всегда используете подстановочные знаки с универсальными подстановочными знаками, даже если параметр типа реализует интерфейс.

Если вы посмотрите на класс, который реализует Comparable, вы увидите, что он на самом деле (должен) реализовать Comparable<T> где T сам класс.

Это имеет смысл, если вы подумаете о параметре типа, передаваемом в интерфейс Comparable, и о том, как он используется в методе compareTo().

Как красноречиво указывает PM 77-1, ключевое слово super позволяет классу T или одному из его родителей реализовать Comparable.

Другие вопросы по тегам