public class BinarySearchTree<T extends Comparable<T>>
Формальный аргумент обобщения, в вашем случае T, перечисляет, что требуется, чтобы класс был допустимым T. В вашем случае, как вы сказали, «чтобы быть допустимым T, класс должен реализовывать Comparable» (ключевое слово is «расширяет», но на практике это означает «расширяет или реализует».)
В вашем случае T - Студент. Если мы заменим Студента на T:
public class BinarySearchTree<Student extends Comparable<Student>>
это правда? Студент действительно реализует Comparable?
Если это так, Student соответствует требованию быть T, и поэтому вы можете использовать Student в качестве фактического параметра для формального параметра T.
Если нет, вы получите жалобу компилятора, которую вы видели.
На самом деле, чтобы охватить более сложные ситуации, когда реализация Comparable подкласса выполняется суперклассом, более общей формой будет:
public class BinarySearchTree<T extends Comparable<? super T > >
Так что вам нужно, чтобы Student реализовал Comparable .
Обратите внимание, что я не сказал, что компилятор ищет Student.compareTo
. Это даже не заходит так далеко. Он проверяет, объявлен ли T (в вашем случае, Student) как реализующий Comparable (в вашем случае Comparable ).
Теперь, добавив implements Comparable< Student >
к Student, также заставит компилятор обеспечить наличие метода public int compareTo
для Student. Но без «реализует Comparable», даже если компилятор знает, что есть метод Student.compareTo
, он не знает, что compareTo
- это Comparable.compareTo
.
(Другими словами, мы ищем объявленную реализацию, а не только то, что существует метод с правильным именем и сигнатурой.)