Как реализовать универсальную функцию `max (Comparable a, Comparable b)` в Java?
Я пытаюсь написать общую функцию max, которая принимает два Comparable
s.
До сих пор у меня
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)
Я думаю, что это говорит о том, что ?
in Comparable<?>
может быть интерпретирован как один тип для параметра a, а другой для параметра b, чтобы они не сравнивались.
Как я выкопаю себя из этой дыры?
Ответы
Ответ 1
Для достижения наилучших результатов вы должны использовать public static <T extends Comparable<? super T>> T max(T a, T b)
.
Проблема с <T extends Comparable<?>>
заключается в том, что это говорит о том, что тип T сопоставим с некоторым типом, но вы не знаете, что это за тип. Разумеется, здравый смысл будет диктовать, что класс, реализующий Comparable, должен быть сопоставим по крайней мере с самим собой (т.е. Иметь возможность сравнивать с объектами своего типа), но технически ничего не мешает реализации класса A Comparable<B>
, где A и 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 (который включал бы все T экземпляров). Напомним правило PECS - производитель extends
, потребитель super
- в этом случае Comparable
является потребителем (он принимает объект для сравнения против), поэтому super
имеет смысл.
Это ограничения типов, используемые всеми функциями сортировки и упорядочения в библиотеке Java.
Ответ 2
Вы получаете эту ошибку, потому что Comparable<?>
в основном говорит, что она сопоставима с чем-то без каких-либо специфических особенностей. Вы должны написать Comparable<T>
вместо этого, поэтому компилятор должен знать, что тип T сопоставим с самим собой.
Ответ 3
Отвечая на мой собственный вопрос из связанных с 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;
}
Ответ 4
Я написал для этого класс утилиты. Возможно, вы сочтете это полезным (библиотека Open Source):
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>
Ответ 5
Лучше получить уже внедренный iso создать собственные. Смотрите на Min/Max функцию с двумя сопоставимыми. Простейшим является org.apache.commons.lang.ObjectUtils
:
Comparable<C> a = ...;
Comparable<C> b = ...;
Comparable<C> min = ObjectUtils.min(a, b);