Вопрос по call, parameters, methods, generics, java – Когда полезен параметризованный вызов метода?

16

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

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

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

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

РЕДАКТИРОВАТЬ

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

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

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

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

Только я думаю, что это странно, как все в этой теме думают, что «параметризованный метод» должен быть универсальным методом? Метод с объявленными параметрами является «параметризованным» методом. Универсальный метод - это просто еще один параметризованный метод, в котором тип является одним из таких параметров. Или я что-то пропустил? Martin Andersson
Вы на месте! В ретроспективе заголовок, вероятно, должен был звучать так: «Когда вызов метода с аргументами типа, которые нельзя предположить, полезен?» Johann-Christoph Jacob

Ваш Ответ

4   ответа
8

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

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

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

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

вы не делаете параметризованный вызов метода в любом месте этого кода newacct
1

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

public static <T extends Comparable> T max(T one, T two) {
    if (one.compareTo(two) > 0) {
        return one;
    } else {
        return two;
    }
}
вы не делаете параметризованный вызов метода в любом месте этого кода newacct
Да, согласен. Не нужно дополнительно указывать класс. Aleksejs Mjaliks
Предполагая, что метод является членом класса Aggregator, и параметр универсального типа T добавляется в Comparable в объявлении, тогда я могу назвать его просто как Aggregator.max (new Integer (5), new Integer (10)); Никаких параметров не требуется при вызове. Johann-Christoph Jacob
15

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

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

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

отличный ответ, особенно использование Varargs Johann-Christoph Jacob
13

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

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

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

@marcolopes, пожалуйста, поясните это на примере. Johann-Christoph Jacob
@Arne - давно я не вызывал его с параметром, но я знаю, что у меня возникла какая-то ошибка, которая вызывала у моего коллегу ошибку. Есть вероятность, что это был статический анализ кода. Я не могу проверить это в течение нескольких часов, но попробую позже. justkt
Я почти уверен, что компилятор никогда не выдаст это предупреждение, что вызывает 'emptyList' таким образом. Я включил предупреждения для дженериков и не получаю предупреждения. Arne Deutsch
Я не могу воспроизвести это предупреждение на моей установке. Даже с параметром -Xlint. Это, вероятно, вызвано различиями компилятора. Я использую javac 1.6.0_20 из Sun JDK для Linux. Johann-Christoph Jacob

Похожие вопросы