Когда полезен параметризованный вызов метода? - PullRequest
16 голосов
/ 06 мая 2010

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

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

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

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


EDIT

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

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

Следующий пример демонстрирует это поведение:

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 ]

15 голосов
/ 06 мая 2010

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

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

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

13 голосов
/ 06 мая 2010

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

List<String> anEmptyStringList = Collections.<String>emptyList();
Set<Integer> unmodifiableCopy = Collections.<Integer>unmodifiableSet(originalSet);

Итак, когда вы хотите использовать универсальный тип в другом месте, вы хотите использовать эти вызовы методов. Они предотвращают предупреждения компилятора при использовании шаблонов.

8 голосов
/ 06 мая 2010

Это, вероятно, наиболее полезно, когда вы берете коллекцию некоторого типа и возвращаете некоторое подмножество этой коллекции.

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

Edit:

В целом, это полезно, когда вы хотите вернуть определенный тип, или если вы хотите связать типы двух или более параметров в общем виде.

1 голос
/ 06 мая 2010

Например, когда вам нужен какой-то универсальный метод для сравнения:

public static <T extends Comparable> T max(T one, T two) {
    if (one.compareTo(two) > 0) {
        return one;
    } else {
        return two;
    }
}
...