Проблема с <T расширяет Comparable <? супер T >> - PullRequest
4 голосов
/ 15 июля 2011

У меня есть три класса: 1.класс Algorithm, имеющий max() нахождение максимального значения в Collection:

public class Algorithm {

    public static <T extends Comparable<T>> T max(Collection<? extends T> coll) {
        T max = coll.iterator().next();

        for (T elm : coll) {
            if (max.compareTo(elm) < 0)
                max = elm;
        }

        return max;
    }
}

2.Класс Fruit:

public class Fruit implements Comparable<Fruit> {
    private String name;
    private int size;

    public Fruit(String name, int size) {
        this.name = name;
        this.size = size;
    }

    public int compareTo(Fruit that) {
        if (size < that.size)
            return -1;
        else if (size == that.size)
            return 0;
        else
            return 1;
    }
}

3.класс Apple расширение Fruit:

public class Apple extends Fruit {
    public Apple(int size) {
        super("Apple", size);
    }
}

Теперь вопрос такой:

public class Main
{
    public static void main(String[] args) {        
        Apple a1 = new Apple(10);
        Apple a2 = new Apple(34);

        List<Apple> apples = Arrays.<Apple>asList(a1, a2);

        System.out.println(Collections.max(apples).size);
    }
}

Согласно этому посту Java - Синтаксис Вопрос: Что такое Я должен написать это так: public static <T extends Comparable<? super T>> T max(Collection<? extends T> coll). Но теперь он работает нормально. Почему? Класс Apple не реализует Comparable<Apple> и отсутствует super.

[UPDATE]
Книга обобщений и коллекций Java гласит:

Без подстановочного знака super, найдя максимум List<Apple> было бы незаконно, даже если найти максимум List<Fruit> допускается.

Ответы [ 3 ]

5 голосов
/ 15 июля 2011

Предположим, мы изменили метод max следующим образом:

<T extends Comparable<T>> T max(Collection<? extends T> coll)

Вы не сможете получить max из List<Apple>, поскольку Apple не реализует Comparable<Apple>,он реализует Comparable<Fruit>.Но мы с вами прекрасно знаем, что Apple знает, как сравнивать себя с другим Fruit, потому что он унаследовал эту функциональность.

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

<T extends Comparable<? super T>> T max(Collection<? extends T> coll)

Это означает, что мы принимаем любой класс T такой, что:

  1. T implements Comparable<T>, или ...
  2. T implements Comparable<X> для некоторых X, таких, что X является суперклассом T

Чтобы найти max, мы должны быть уверены, что любой экземпляр Tможет безопасно принять другой экземпляр T в качестве аргумента своего метода compare.

В первом сценарии очевидно, что любой экземпляр T может безопасно принять другой экземпляр T какаргумент к его compare(T) методу.

Во втором сценарии любой экземпляр T может безопасно принять другой экземпляр T в качестве аргумента к его compare(X) методу, потому что все экземпляры T также являются экземплярами X.

Ваш пример иллюстрирует второй сценарийio, где T соответствует Apple и X соответствует Fruit.

1 голос
/ 15 июля 2011

Вы используете Collections.max(apples) вместо Algorithm.max.

Collections.max имеет немного другое объявление:

public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
0 голосов
/ 24 сентября 2017

извините за возвращение, но я думаю, что это важно. Ваш код перестал работать должным образом при изменении с Collections.max () на Algorithm.max ()? Я выполнил аналогичный тест в jdk8, и я не понимаю, почему он работает нормально, а в соответствии с Java Generics и Collections - нет.

У меня есть абстрактный класс Fruit (реализующий Comparable):

public abstract class Fruit implements Comparable<Fruit> {
    private String name;
    private int size;

    public Fruit(String name, int size) {
        this.name = name;
        this.size = size;
    }

    public int compareTo(Fruit that) {
        if (size < that.size)
            return -1;
        else if (size == that.size)
            return 0;
        else
            return 1;
    }
}

Тогда у меня есть Apple, расширяющий класс Fruit:

public class Apple extends Fruit {
    public Apple(String name, int size) {
        super(name, size);
    }
}

И наконец:

 public class GenericsTest {

    @Test
    public void test1() {
        final Apple a1 = new Apple("apple1", 50);
        final Apple a2 = new Apple("apple2", 70);
        final Apple a3 = new Apple("apple3", 34);

        final List<Apple> apples = Lists.newArrayList(a1, a2, a3);

        System.out.println(GenericsTest.max(apples).getSize());
    }

    private static <T extends Comparable<T>> T max(Collection<? extends T> coll) {
        T max = coll.iterator().next();

        for (T elm : coll) {
            if (max.compareTo(elm) < 0)
                max = elm;
        }

        return max;
    }
}

Код работает, а нет? super T в сигнатуре метода max, а список имеет тип Apple. Согласно цитате, которую вы упомянули, она не должна работать. Я, кажется, озадачен здесь ...

...