Разница заключается в возвращаемом типе, особенно под влиянием вывода , причем тип может быть типом иерархически между типами Comparable и типом List. Позвольте мне привести пример:
class Top {
}
class Middle extends Top implements Comparable<Top> {
@Override
public int compareTo(Top o) {
//
}
}
class Bottom extends Middle {
}
Используя подпись, которую вы предоставили:
public static <T extends Comparable<? super T>> T max(List<? extends T> list)
, мы можем закодировать это без ошибок, предупреждений или (что важно) приведения:
List<Bottom> list;
Middle max = max(list); // T inferred to be Middle
И если вы нуждаетесь в результате Middle
, без вывода, вы можете явно ввести вызов в Middle
:
Comparable<Top> max = MyClass.<Middle>max(list); // No cast
или перейти к методу, который принимает Middle
(где вывод не будет работать)
someGenericMethodThatExpectsGenericBoundedToMiddle(MyClass.<Middle>max(list));
Я не знаю, помогает ли это, но чтобы проиллюстрировать типы компилятора как разрешенные / предположим, подпись будет выглядеть так (не это, конечно, компилируется):
public static <Middle extends Comparable<Top>> Middle max(List<Bottom> list)