? это просто подстановочный знак. Это означает, что метод будет принимать коллекцию любого типа.
<T>
является параметром типа для метода. По сути, это присвоение подстановочного знака имени, на которое затем можно ссылаться в другом месте в объявлении и определении метода.
Лучшей иллюстрацией различия будет, если тип возвращаемого значения метода изменяется в зависимости от типа, который был передан.
Скажем, вы начали с метода, подобного
Object getRandomElement( Collection<?> c )
Это будет принимать любую коллекцию, но нет способа ограничить ее тип возвращаемого значения. Поэтому вызывающий объект должен будет привести результат обратно к тому типу, который он ожидал, - который должен работать, но выдает опасные предупреждения о преобразовании типов.
С параметром типа вы вместо этого напишите
<T> T getRandomElement( Collection<T> c )
В этом случае, если вы вызываете этот метод с Collection<String>
, компилятор знает, что он вернет String
.