Вызов метода Java может быть параметризован как в следующем коде:
class Test
{
<T> void test()
{
}
public static void main(String[] args)
{
new Test().<Object>test();
// ^^^^^^^^
}
}
Я узнал, что это возможно от диалогового окна Параметров средства форматирования Java Eclipse и задалось вопросом, существуют ли какие-либо случаи, где это полезно или необходимо.
Править
На основе превосходного ответа Arne я придумал следующее заключение:
В дополнение к улучшенной безопасности типов, поскольку пример Arne иллюстрирует, что вызов параметризованного метода позволяет Вам указать тип общей базы аргументов методов, которые должны быть типом контейнерных элементов. Этот тип обычно заключается автоматически компилятором к самому определенному типу общей базы. Путем параметризации вызова метода может быть переопределено это поведение. Вызов параметризованного метода может требоваться, если существует несколько общих типов, заключенных компилятором.
Следующий пример демонстрирует что поведение:
import java.util.Arrays;
import java.util.List;
class Test
{
public static void main(String[] args)
{
Integer a=new Integer(0);
Long b=new Long(0);
List<Object> listError=Arrays.asList(a, b);
//error because Number&Comparable<?> is not Object
List<Object> listObj=Arrays.<Object>asList(a, b);
List<Number> listNum=Arrays.<Number>asList(a, b);
List<Comparable<?>> listCmp=Arrays.<Comparable<?>>asList(a, b);
}
}
Это поведение определяется в абзацах 8.4.4 и 15.12.2.7 Выпуска Трети Спецификации языка Java, но не понятное.
Я никогда не использовал это на практике, но вы можете себе представить, что используете это для безопасности типа. Рассмотрим следующий метод:
<T> void method(T... items) {
List<T> list = new ArrayList<T>();
for (T item : items)
list.add(item);
System.out.println(list);
}
Вы можете вызвать его следующим образом:
o.<Object>method("Blah", new Long(0));
o.<Number>method(new Integer(100), new Long(0));
Но это вызовет ошибку компилятора:
o.<Number>method("String", new Long(0));
Таким образом, у вас есть универсальный метод, который является типобезоподборным и может использоваться для каждого Object, не ограничиваясь парикулярным интерфейсом или классом.
Вызовы параметризованных методов полезны, когда вы хотите разрешить использование различных типов без преобразования типов. Например, вспомогательный класс Collections широко использует вызовы параметризованных методов. Если вы хотите создать новую универсальную коллекцию, используя один из их вспомогательных методов, несколько примеров:
List<String> anEmptyStringList = Collections.<String>emptyList();
Set<Integer> unmodifiableCopy = Collections.<Integer>unmodifiableSet(originalSet);
Итак, если вы хотите иметь возможность использовать универсальный тип в другом месте, вы хотите использовать эти вызовы методов. Они предотвращают появление предупреждений компилятора при использовании дженериков.
Это, вероятно, наиболее полезно, когда вы берете коллекцию определенного типа и возвращаете некоторое подмножество этой коллекции.
<T> List<T> filter(Collection<? extends T> coll, Predicate<? super T> pred) {
List<T> returnList = new ArrayList<T>();
for(T t : coll) {
if(pred.matches(t)){
returnList.add(t);
}
}
return returnList;
}
Изменить:
В общем, это полезно, когда вы хотите вернуть определенный тип или хотите связать типы двух или более параметров общим способом.
Например, когда вам нужен какой-то универсальный метод для сравнений:
public static <T extends Comparable> T max(T one, T two) {
if (one.compareTo(two) > 0) {
return one;
} else {
return two;
}
}