Подпись метода Collections.min/max

В Java класс Collections содержит следующий метод:

public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> c)

Его подпись хорошо известна своим расширенным использованием дженериков, настолько, что упоминается в Java в двух словах и в официальном Учебном пособии Sun Generics.

Однако я не смог найти убедительного ответа на следующий вопрос:

Почему формальный параметр типа Collection<? extends T>, скорее чем Collection<T>? Какая дополнительная польза?

Ответы

Ответ 1

Одним из преимуществ ? является то, что он запрещает добавление элементов в Collection

Ответ 2

Вывод типа - это сложная тема, которую я признаю, что я об этом не знаю. Однако рассмотрите этот пример:

public class ScratchPad {
   private static class A implements Comparable<A> {
     public int compareTo(A o) { return 0; }
   }
   private static class B extends A {}
   private static class C extends B {}

   public static void main(String[] args)
   {
     Collection<C> coll = null;
     B b = Scratchpad.<B>min(coll);
   }

   public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> c)  {
     return null;
   }

   //public static <T extends Object & Comparable<? super T>> T min(Collection<T> c) {
   //  return null;
   //}
}

Учтите, что первая подпись min() позволяет компиляции вызова, а вторая - нет. Это не очень практичный пример, так как нужно спросить, почему я должен явно вводить метод в <B>, но, возможно, существует неявный вывод, где B будет выведенным типом.

Ответ 3

Я думаю, что на самом деле это не дает вам ничего больше для этого метода, однако его хорошая привычка вступать, когда T является частью класса, а не только статическим методом.

Они включают его здесь, чтобы он мог стать новым соглашением, в котором каждый родословный должен быть расширен на?

Класс T должен следовать за PECS: Что такое PECS (продюсер продлевает потребительский супер)?

Но статическому методу не нужно (по крайней мере, параметры, всегда возвращаемое значение)

Ответ 4

Это поддержка устаревшей сигнатуры метода в Java 1.4 (и раньше).

До появления Java 5 сигнатура для этих методов была

public static Object min ( Collection c );

С несколькими ограничениями правила стирания делают первую границу необработанным типом метода, поэтому без Object & подпись будет

public static Comparable min ( Collection c );

и устаревший код сломается.

Это взято из книги генералов и коллекций O'Reilly Java, глава 3.6

Ответ 5

Основываясь на комментариях, которые я поставил на ответ Марка, если у вас есть что-то вроде

class Play {
    class A implements Comparable<A> {
        @Override
        public int compareTo(A o) {
            return 0;
        }
    }

    class B extends A {
    }

    class C extends A {
    }

    public static <T extends Object & Comparable<? super T>> T min(
            Collection<? extends T> c) {
        Iterator<? extends T> i = c.iterator();
        T candidate = i.next();

        while (i.hasNext()) {
            T next = i.next();
            if (next.compareTo(candidate) < 0)
                candidate = next;
        }
        return candidate;
    }

    public static List<? extends A> getMixedList() {
        Play p = new Play();
        ArrayList<A> c = new ArrayList<A>();
        c.add(p.new C());
        c.add(p.new B());
        return c;
    }

    public static void main(String[] args) {
        ArrayList<A> c = new ArrayList<A>();
        Collection<? extends A> coll = getMixedList();
        A a = Play.min(coll);
    }
}

Ясно, что min возвращает объект типа A (фактическая подпись <A> A Play.min(Collection<? extends A> c)). Если вы оставите min(Collection<T>) без части расширения, то Play.min(coll) будет иметь следующую подпись <? extends A> ? extends A Play.min(Collection<? extends A> c), которая не так понятна.