Как реализовать универсальную функцию `max(Comparable a, Comparable b)` в Java?

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

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

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, так что их нельзя сравнивать.

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

4 ответа

Решение

Для достижения наилучших результатов вы должны использовать 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.

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

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

Comparable<C> a = ...;
Comparable<C> b = ...;
Comparable<C> min = ObjectUtils.min(a, b);

Отвечая на мой собственный вопрос из сгенерированных связанных ссылок SO - это, кажется, тонкий дубликат Fun с дженериками 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;
}

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

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> 
Другие вопросы по тегам