Как реализовать универсальную функцию `max (Comparable a, Comparable b)` в Java? - PullRequest
14 голосов
/ 23 июня 2011

Я пытаюсь написать универсальную функцию max, которая занимает два Comparable с.

Пока у меня есть

public static <T extends Comparable<?>> T max(T a, T b) {
    if (a == null) {
        if (b == null) return a;
        else return b;
    }
    if (b == null)
        return a;
    return a.compareTo(b) > 0 ? a : b;
}

Это не компилируется с

The method compareTo(capture#5-of ?) in the type Comparable<capture#5-of ?> is not applicable for the arguments (T)

Я думаю, это говорит о том, что ? в Comparable<?> можно интерпретировать как один тип для параметра a, а другой для параметра b, так что их нельзя сравнивать.

Как мне выкопать себя из этой ямы?

Ответы [ 5 ]

28 голосов
/ 24 июня 2011

Для достижения наилучших результатов вы должны использовать public static <T extends Comparable<? super T>> T max(T a, T b).

Проблема с <T extends Comparable<?>> заключается в том, что это говорит о том, что тип T сопоставим с некоторым типом, но вы не знаете, что это за тип.Конечно, здравый смысл должен диктовать, что класс, который реализует Comparable, должен быть в состоянии быть сопоставимым хотя бы с самим собой (то есть иметь возможность сравнивать с объектами своего собственного типа), но технически ничто не мешает классу A реализовать Comparable<B>где А и В не имеют ничего общего друг с другом.<T extends Comparable<T>> решает эту проблему.

Но есть небольшая проблема с этим.Предположим, что класс X реализует Comparable<X>, и у меня есть класс Y, который расширяет X. Таким образом, класс Y автоматически реализует Comparable<X> путем наследования.Класс Y также не может реализовать Comparable<Y>, потому что класс не может реализовать интерфейс дважды с различными параметрами типа.На самом деле это не проблема, поскольку экземпляры Y являются экземплярами X, поэтому Y сопоставим со всеми экземплярами Y. Но проблема в том, что вы не можете использовать тип Y с вашей функцией <T extends Comparable<T>> T max(T a, T b), потому что Y не реализуетComparable<Y>.Границы слишком строгие.<T extends Comparable<? super T>> устраняет проблему, поскольку достаточно, чтобы T было сопоставимо с некоторым супертипом T (который включал бы все экземпляры T).Вспомните правило PECS - производитель extends, потребитель super - в этом случае Comparable является потребителем (для сравнения требуется объект), поэтому super имеет смысл.

Этоэто границы типов, используемые всеми функциями сортировки и упорядочения в библиотеке Java.

4 голосов
/ 23 июня 2011

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

1 голос
/ 23 июня 2011

Я написал для этого служебный класс. Может быть, вы найдете это полезным (библиотека с открытым исходным кодом):

http://softsmithy.sourceforge.net/lib/docs/api/org/softsmithy/lib/util/Comparables.html

Сайт:

http://www.softsmithy.org

Скачать:

http://sourceforge.net/projects/softsmithy/files/softsmithy/

Maven:

<dependency>  
    <groupid>org.softsmithy.lib</groupid>  
    <artifactid>lib-core</artifactid>  
    <version>0.1</version>  
</dependency> 
1 голос
/ 23 июня 2011

Отвечая на мой собственный вопрос из сгенерированных связанных ссылок SO - это, кажется, тонкий дубликат Удовольствия от обобщений Java , хотя я думаю, вы не можете обвинить меня в том, что я не нашел его по названию!

Самое простое решение -

public static <T extends Comparable<T>> T max(T a, T b) {
    if (a == null) {
        if (b == null) return a;
        else return b;
    }
    if (b == null)
        return a;
    return a.compareTo(b) > 0 ? a : b;
}
0 голосов
/ 05 мая 2019

Лучше получать уже реализованные iso создавать собственные.См. Мин. / Макс. Функция с двумя сопоставимыми .Простейшим является org.apache.commons.lang.ObjectUtils:

Comparable<C> a = ...;
Comparable<C> b = ...;
Comparable<C> min = ObjectUtils.min(a, b);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...