Подтвердить что ты не робот

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

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

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

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

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


ИЗМЕНИТЬ

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

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

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

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, но не легко понято.

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

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

Ответ 3

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

<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:

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

Ответ 4

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

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