Что такое <? супер T> синтаксис?

У меня возникли проблемы с пониманием следующего синтаксиса:

public class SortedList< T extends Comparable< ? super T> > extends LinkedList< T >

Я вижу, что класс SortedList расширяет LinkedList. Я просто не знаю, что

T extends Comparable< ? super T>

средства.

Мое понимание этого до сих пор заключается в том, что тип T должен быть типом, который реализует Comparable... но что такое < ? super T >?

Ответ 1

super в Generics - противоположность расширений. Вместо того, чтобы говорить, что сопоставимый общий тип должен быть подклассом T, он говорит, что он должен быть суперклассом T. Различие важно, потому что extends говорит вам, что вы можете выбраться из класса (вы получаете хотя бы это, возможно, подкласс). супер говорит вам, что вы можете поместить в класс (самое большее это, возможно, суперкласс).

В этом конкретном случае то, что он говорит, заключается в том, что тип должен реализовывать сопоставимые данные о себе или своем суперклассе. Поэтому рассмотрим java.util.Date. Он реализует Comparable<Date>. Но как насчет java.sql.Date? Он также реализует Comparable<java.util.Date>.

Без супер-подписи SortedList не сможет принять тип java.sql.Date, потому что он не реализует Comparable самого себя, а скорее супер-класс.

Ответ 2

Это низкоуровневый шаблон.

JLS 4.5.1 Типы аргументов и подстановочные знаки

Подстановочные знаки полезны в ситуациях, когда требуется только частичное знание параметра типа. [...] Верхняя граница обозначается синтаксисом:

? extends B

где B - верхняя граница. [...] допустимо объявлять нижние границы подстановочного знака, используя синтаксис:

? super B

где B - нижняя граница.

A List<? super Integer>, например, включает List<Integer>, List<Number> и List<Object>.

Подстановочные знаки используются для создания более гибких и гибких дженериков; границы используются для поддержания безопасности типов.

См. также


Как это полезно в <T extends Comparable<? super T>>, это когда у вас есть что-то вроде Cat extends Animal implements Comparable<Animal>.

Посмотрите на подпись Collections.sort

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

Следовательно, с List<Cat> listOfCat вы можете теперь Collections.sort(listOfCat).

Если бы оно было объявлено следующим образом:

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

тогда вам нужно будет Cat implements Comparable<Cat> использовать sort. Используя ? super T ограниченный подстановочный знак, Collections.sort становится более гибким.

См. также

  • Эффективное Java 2nd Edition, пункт 28: Используйте ограниченные групповые символы для повышения гибкости API
    • Кроме того, принцип PECS: "производитель extends потребитель super"

Ответ 3

Это означает, что T должен реализовать Comparable<T itself or one of T superclasses> Смысл в том, что, поскольку SortedList сортируется, он должен знать, как сравнить два класса своего дженериков T. Поэтому T должен реализовать Comparable<T itself or one of T superclasses>

Ответ 4

Это означает, что тип T должен реализовать Comparable of T или один из его суперклассов.

Например, если A extends B, если вы хотите использовать SortedList<A>, A должен реализовать Comparable<A> или Comparable<B>, или на самом деле просто Comparable.

Это позволяет создать список A с любым допустимым компаратором.

Ответ 5

Рассмотрим следующий пример:

  • Использование параметра типа, определенного в объявлении класса

    открытый класс ArrayList расширяет AbstractList... {
       public boolean add (E o)//Вы можете использовать "E" здесь ТОЛЬКО, потому что он уже определен как часть класса

  • Использование параметра типа, который НЕ был указан в объявлении класса

    public <T extends Animal> void takeThing(ArrayList<T> list)
                                                // Here we can use <T> because we declared "T" earlier in the method declaration                  
    

    Если сам класс не использует параметр типа, вы все равно можете указать его для метода, объявив его в действительно необычном (но доступном) пространстве - перед типом возвращаемого значения. Этот метод говорит, что T может быть "любым типом животных".

ПРИМЕЧАНИЕ:

public <T extends Animal> void takeThing(ArrayList<T> list)             

is NOT same as              

public void takeThing(ArrayList<Animal> list)

Оба являются законными, но они разные. Первый указывает, что вы можете передать объект ArrayList, созданный как Animal или любой подтип Animal, такой как ArrayList, ArrayList или ArrayList. Но вы можете передать ArrayList только во втором, а НЕ любой из подтипов.