2010-05-06 2 views
13

метод 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); 
    } 
} 

Такое поведение определяется в пунктах Java Language Specification Третье издание 8.4.4 и 15.12.2.7, но не легко понять.

+0

Является ли это только тем, что думает, что странно, как все в этой теме, кажется, считают, что «параметризованный метод» должен быть универсальным методом? Метод, который имеет объявленные параметры, является «параметризованным» методом. Общий метод - это еще один параметризованный метод, в котором тип является одним из таких параметров. Или я что-то пропустил? –

+0

Вы находитесь на месте! Оглядываясь назад, название должно быть, вероятно, «Когда вызов метода с аргументами типа, который нельзя сделать полезным?» –

ответ

13

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

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

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

+0

отличный ответ, особенно использование varargs –

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

Edit:

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

+1

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

13

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

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

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

+1

Не является ли тип коллекции, выведенный из объявления переменных? –

+0

Вы получите предупреждение от компилятора (если вы не отключили его), если вы выполните «Список anEmptyStringList = Collections.emptyList()» без параметра в вызове. Фактически, я впервые узнал об этом от коллеги, который показывал мне, как избавиться от предупреждения. – justkt

+0

Я не могу воспроизвести это предупреждение в моей настройке. Даже с параметром -Xlint. Вероятно, это связано с различиями в компиляторах. Я использую javac 1.6.0_20 от Sun JDK в Linux. –

1

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

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

Предполагая, что этот метод является членом класса Aggregator, а параметр обобщенного типа T добавляется в Comparable в объявление, я могу назвать его просто как Aggregator.max (новое целое число (5), новое целое число (10)); Для вызова не требуется никаких параметров. –

+0

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

+0

Да, согласитесь. Не нужно дополнительно указывать класс. –