2010-05-06 14 views
13

metodo A Java chiamata può essere parametrizzata come nel codice seguente:Quando è utile una chiamata al metodo parametrizzata?

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

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

ho scoperto questo è possibile dalla finestra di impostazioni di Eclipse Java Formatter e mi chiedevo se ci sono dei casi in cui ciò è utile o necessario.


EDIT

Sulla base di risposta eccellente di Arne mi si avvicinò con la seguente conclusione:

Oltre a migliorare la sicurezza di tipo come esempio di Arne illustra una chiamata di metodo con parametri permette di specificare il tipo di base comune degli argomenti dei metodi che dovrebbero essere il tipo degli elementi del contenitore. Questo tipo viene normalmente inferito automaticamente dal compilatore al tipo di base comune più specifico. Parametrizzando la chiamata al metodo, questo comportamento può essere sovrascritto. Potrebbe essere necessaria una chiamata al metodo parametrizzata se sono presenti più tipi comuni inferiti dal compilatore.

Il seguente esempio dimostra che il comportamento:

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

Questo comportamento è definito nei paragrafi linguaggio Java Specification Terza edizione 8.4.4 e 15.12.2.7 ma non facilmente comprensibile.

+0

Sono solo io a pensare che sia strano come tutti in questa discussione sembrino pensare che un "metodo parametrizzato" debba essere un metodo generico? Un metodo con parametri dichiarati è un metodo "parametrizzato". Un metodo generico è solo un altro metodo parametrizzato in cui il tipo è uno di questi parametri. O mi sono perso qualcosa? –

+0

Sei perfetto! Con il senno di poi il titolo dovrebbe probabilmente essere stato "Quando è una chiamata di metodo con argomenti di tipo che non possono essere dedotti in modo utile?" –

risposta

13

non ho mai usato questo, in pratica, ma si può immaginare di utilizzare questo tipo per la sicurezza.Si consideri il seguente metodo:

<T> void method(T... items) { 
    List<T> list = new ArrayList<T>(); 
    for (T item : items) 
     list.add(item); 
    System.out.println(list); 
} 

si può chiamare in questo modo:

o.<Object>method("Blah", new Long(0)); 
o.<Number>method(new Integer(100), new Long(0)); 

Ma questo genererà un errore di compilazione:

o.<Number>method("String", new Long(0)); 

in modo da avere un metodo generico che è typesafe e può essere utilizzato per ogni oggetto, non limitato a un'interfaccia o a una classe paricolare.

+0

ottima risposta soprattutto l'uso di vararg –

8

È probabilmente più utile quando si acquisisce una raccolta di un certo tipo e si restituisce un sottoinsieme di tale raccolta.

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

Più in generale, è utile ogni volta che si desidera restituire un tipo specifico, o se si vuole collegare i tipi di due o più parametri in modo generale.

+1

non si sta effettuando una chiamata al metodo con parametri ovunque in quel codice – newacct

13

Le chiamate con metodo parametrico sono utili quando si desidera consentire tipi diversi senza eseguire il cast. Ad esempio, la classe helper Collections fa ampio uso di chiamate di metodo con parametri. Quando si vuole fare una nuova collezione generico utilizzando uno dei loro metodi di supporto, alcuni esempi:

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

Così, quando si vuole essere in grado di utilizzare il tipo generico altrove, si vuole utilizzare tali chiamate di metodo. Impediscono gli avvertimenti del compilatore quando si usano i generici.

+1

Non è comunque il tipo di raccolta dedotto dalla dichiarazione della variabile? –

+0

Si otterrà un cast di avviso dal compilatore (a meno che non siano stati disattivati) se si esegue 'Elenco anEmptyStringList = Collections.emptyList()' senza il parametro nella chiamata. In effetti, l'ho saputo per la prima volta da un collega che mi stava mostrando come sbarazzarmi dell'avvertimento. – justkt

+0

Non riesco a riprodurre questo avviso sul mio setup. Neanche con il parametro -Xlint. Questo è probabilmente causato dalle differenze del compilatore. Io uso javac 1.6.0_20 da Sun JDK su Linux. –

1

Ad esempio, quando avete bisogno di qualche metodo universale per il confronto:

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

Supponendo che il metodo sia membro della classe Aggregator e il parametro di tipo generico T sia aggiunto a Comparable nella dichiarazione, posso chiamarlo semplicemente come Aggregator.max (new Integer (5), new Integer (10)); Nessun parametro richiesto per la chiamata. –

+0

non stai facendo una chiamata di metodo parametrizzata ovunque in quel codice – newacct

+0

Sì, d'accordo. Non c'è bisogno di specificare ulteriormente la classe. –

Problemi correlati