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