Ответ 1
Это очень хороший вопрос. Во-первых, давайте начнем с причины, по которой Collections
используют методы типа
binarySearch(List<? extends Comparable<? super T>> list, T key)
В самом деле, почему не просто
binarySearch(List<? extends Comparable<T>> list, T key)
Причиной этого является принцип PECS: продюсер продюсеров, потребительский супер. Что делает binarySearch
? Он считывает элементы из списка и затем сравнивает их, передавая их значения функции compareTo
. Поскольку он читает элементы, список действует как производитель, и, следовательно, первая часть-продюсер расширяет. Это очевидно, так как насчет части "Потребительская супер"?
Потребитель Super в основном означает, что, если вы собираетесь передавать значения какой-либо функции, вам все равно, принимает ли он точный тип вашего объекта или какой-либо его суперкласс. Итак, что говорит декларация binarySearch
: я могу искать что угодно, если что-либо может быть передано методу compareTo
элементов списка.
В случае сортировки это не так очевидно, потому что элементы сравниваются только друг с другом. Но даже тогда, что, если Base
действительно реализует Comparable<Base>
(и делает все сравнение) и A
и B
просто расширяется Base
, не трогая сравнение каким-либо образом? Тогда вы не сможете сортировать списки A
и B
, потому что они не реализуют Comparable<A>
и Comparable<B>
соответственно. Вам придется переопределять весь интерфейс каждый раз, когда вы подклассы!
Другой пример: что, если кто-то захотел выполнить двоичный поиск в списке, содержащем экземпляры какого-либо класса, который даже не расширяет ваш Base
?
class BaseComparable implements Comparable<Base> {
private final Base key;
// other fields
BaseComparable(Base key, ...) {
this.key = key;
// other fields initialization
}
@Override
public int compareTo(Base otherKey) {
return this.key.compareTo(otherKey);
}
};
И теперь они хотят использовать экземпляр A
в качестве ключа для этого двоичного поиска. Они могут делать это только из-за части ? super T
. Обратите внимание, что этот класс не знает, является ли ключ A
или B
, поэтому он не может реализовать Comparable<A/B>
.
Что касается вашего примера, я думаю, что это всего лишь пример плохого дизайна. К сожалению, я не вижу возможности предотвратить такие вещи, не нарушая принцип PECS и/или ограничивая уже ограниченную функциональность Java-дженериков.