2010-05-06 4 views
13

Un Java appel de méthode peut être paramétrés comme dans le code suivant:Quand un appel de méthode paramétré est-il utile?

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

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

J'ai découvert cela est possible à partir des paramètres Eclipse Java Formatter dialogue et je me demandais s'il y a des cas où cela est utile ou nécessaire.


EDIT

Basé sur une excellente réponse de Arne je suis venu à la conclusion suivante:

En plus d'améliorer la sécurité de type que l'exemple de Arne illustre un appel de méthode paramétrés vous permet de spécifier le type de base commun des arguments méthodes qui devrait être le type des éléments du conteneur. Ce type est normalement déduit automatiquement par le compilateur au type de base commun le plus spécifique. En paramétrant l'appel de la méthode, ce comportement peut être surchargé. Un appel de méthode paramétrée peut être requis s'il existe plusieurs types communs inférés par le compilateur.

L'exemple suivant montre que le comportement:

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

Ce comportement est défini dans la spécification du langage Java Troisième édition paragraphes 8.4.4 et 15.12.2.7, mais pas facile à comprendre.

+0

Est-ce seulement moi qui pense que c'est bizarre que tout le monde dans ce fil semble penser qu'une "méthode paramétrée" doit être une méthode générique? Une méthode qui a des paramètres déclarés est une méthode "paramétrée". Une méthode générique est juste une autre méthode paramétrée où le type est un de ces paramètres. Ou ai-je manqué quelque chose? –

+0

Vous êtes sur! Avec le recul, le titre aurait probablement dû être "Quand est un appel de méthode avec des arguments de type qui ne peuvent être déduits utiles?" –

Répondre

13

Je n'ai jamais utilisé dans la pratique, mais vous pouvez imaginer l'utiliser pour la sécurité de type.Considérez la méthode suivante:

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

Vous pouvez l'appeler ainsi:

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

Mais cela soulèvera une erreur du compilateur:

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

Vous avez donc une méthode générique qui est typesafe et peut être utilisé pour chaque objet, non limité à une interface ou à une classe particulière.

+0

excellente réponse en particulier l'utilisation de Varargs –

8

Il est probablement plus utile lorsque vous prenez une collection de quelque type, et renvoyez un sous-ensemble de cette collection.

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

Plus généralement, il est utile chaque fois que vous souhaitez retourner un type spécifique ou que vous voulez lier les types de deux ou plusieurs paramètres d'une manière générale.

+1

vous ne faites pas un appel de méthode paramétré n'importe où dans ce code – newacct

13

Les appels de méthode paramétrés sont utiles lorsque vous souhaitez autoriser différents types sans conversion. Par exemple, la classe d'assistance Collections utilise largement les appels de méthode paramétrés. Lorsque vous souhaitez effectuer une nouvelle collection générique en utilisant une de leurs méthodes d'aide, quelques exemples:

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

Alors, vous voulez quand vous voulez être en mesure d'utiliser le type générique ailleurs d'utiliser ces appels de méthode. Ils empêchent les avertissements du compilateur lors de l'utilisation de génériques.

+1

Le type de collection n'est-il pas déduit de la déclaration de variable? –

+0

Vous obtiendrez un cast d'avertissement du compilateur (sauf si vous les avez désactivés) si vous faites 'Liste anEmptyStringList = Collections.emptyList()' sans le paramètre dans l'appel. En fait, j'ai d'abord appris à ce sujet d'un collègue qui m'a montré comment se débarrasser de l'avertissement. – justkt

+0

Je ne peux pas reproduire cet avertissement sur ma configuration. Pas même avec le paramètre -Xlint. Cela est probablement dû aux différences du compilateur. J'utilise javac 1.6.0_20 du Sun JDK sous Linux. –

1

Par exemple, lorsque vous avez besoin d'méthode universelle pour les comparaisons:

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

En supposant que la méthode est membre de la classe Aggregator et que le paramètre de type générique T est ajouté à Comparable dans la déclaration, je peux l'appeler simplement Aggregator.max (new Integer (5), new Integer (10)); Aucun paramètre requis pour l'appel. –

+0

vous ne faites pas un appel de méthode paramétré n'importe où dans ce code – newacct

+0

Oui, d'accord. Pas besoin de spécifier en plus la classe. –

Questions connexes