Когда полезен параметризованный вызов метода?

вызов метода Java может быть параметризован, как в следующем коде:

class Test
{
    <T> void test()
    {
    }

    public static void main(String[] args)
    {
        new Test().<Object>test();
        //         ^^^^^^^^
    }
}

я узнал, что это возможно из диалога настроек форматирования Eclipse Java и задался вопросом, есть ли какие-либо случаи, когда это полезно или необходимо.


редактировать

основываясь на превосходном ответе Арне, я пришел к следующему выводу:

в дополнение к улучшенной безопасности типов, как пример Арне иллюстрирует параметризованный метод call позволяет указать общий базовый тип аргументов методов, который должен быть типом элементов контейнера. Этот тип обычно автоматически выводится компилятором к наиболее определенному общему базовому типу. При параметризации вызова метода это поведение может быть переопределено. Параметризованный вызов метода может потребоваться, если компилятор выводит несколько общих типов.

в следующем примере показано, что поведение:

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 третьего издания, но не легко понять.

4 ответов


Я никогда не использовал это на практике, но вы можете себе представить, чтобы использовать это для безопасности типа. Рассмотрим следующий метод:

<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));

Так что у вас есть универсальный метод, который является достаточно безопасным и может быть использован для каждого объекта, не ограничиваясь нужный интерфейс или класс.


параметризованные вызовы методов полезны, когда вы хотите разрешить различные типы без приведения. Например,коллекции вспомогательный класс широко использует параметризованные вызовы метода. Если вы хотите создать новую общую коллекцию, используя один из их вспомогательных методов, несколько примеров:

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;
    }
}