Différence entre le type générique et le type de Joker

je suis un internaute novice dans Generic et ma question Est: quelle différence entre deux fonctions:

fonction 1:

public static <E> void funct1  (List<E> list1) {

}

fonction 2:

public static void funct2(List<?> list) {

}

Merci.

40
demandé sur Fio 2012-06-08 08:38:49

7 réponses

la première signature dit: list1 est une liste de Es.

Le deuxième dit: liste est une Liste d'instances d'un certain type, mais nous ne connaissons pas le type.

la différence devient évidente lorsque nous essayons de changer la méthode de sorte qu'il prend un deuxième argument, qui devrait être ajouté à la liste à l'intérieur de la méthode:

import java.util.List;

public class Experiment {
    public static <E> void funct1(final List<E> list1, final E something) {
        list1.add(something);
    }

    public static void funct2(final List<?> list, final Object something) {
        list.add(something); // does not compile
    }
}

le premier fonctionne bien. Et vous ne pouvez pas changer le deuxième argument en quoi que ce soit en fait la compilation.

en fait je viens de trouver une encore plus belle démonstration de la différence:

public class Experiment {
    public static <E> void funct1(final List<E> list) {
        list.add(list.get(0));
    }

    public static void funct2(final List<?> list) {
        list.add(list.get(0)); // !!!!!!!!!!!!!! won't compile !!!!!!!!!
    }
}

on pourrait se demander pourquoi nous avons besoin de <?> alors qu'il ne restreint que ce que nous pouvons en faire (comme @Babu_Reddy_H l'a fait dans les commentaires). Je vois les avantages suivants de la version Joker:

  • L'appelant a à savoir moins sur l'objet qu'il passe. Par exemple, si j'ai une carte des listes: Map<String, List<?>> je peux passer ses valeurs à votre fonction sans spécifier le type des éléments de la liste. So

  • si je distribue des objets paramétrés comme celui-ci, je limite activement ce que les gens savent de ces objets et ce qu'ils peuvent en faire (à condition qu'ils restent à l'écart du moulage dangereux).

ces deux-là ont un sens quand je les combine: List<? extends T> . Par exemple, envisager une méthode List<T> merge(List<? extends T>, List<? extends T>) , qui fusionne les deux listes à une nouvelle liste de résultats. Bien sûr, vous pourriez présenter deux autres paramètres de type, mais pourquoi voudriez-vous? Ce serait trop spécifier des choses.

  • enfin les caractères génériques peuvent avoir des limites inférieures, donc avec les listes vous pouvez faire fonctionner la méthode add , alors que get ne vous donne rien d'utile. Bien sûr, cela déclenche la question suivante: pourquoi les génériques n'ont-ils pas des limites inférieures?

pour un plus en profondeur réponse voir: quand utiliser des méthodes génériques et quand utiliser wild-card? et http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#FAQ203

32
répondu Jens Schauder 2017-05-23 12:02:34

Génériques rend la collection plus sécurisé.

List<E> : voici le paramètre Type, qui peut être utilisé pour déterminer le type de contenu de la liste, mais il y avait No façon de vérifier ce qui était le contenu pendant le runtime .

Generics are checked only during compilation time.

<? extends String> : il a été spécialement construit en java, pour traiter le problème qui était avec le paramètre de Type. "? extends String" signifie que cette liste peut avoir

objects which IS-A String.

pour eg:

Animal de la classe La classe de chien s'étend Animal Tiger classe étend Animal

ainsi en utilisant "public void go(ArrayList<Animal> a)" will NOT accept chien ou tigre comme son contenu mais Animal.

"public void go(ArrayList<? extends Animal> a)" est ce qui est nécessaire pour faire le ArrayList take in Dog and Tiger type.

vérifier les références dans Head First Java.

6
répondu Kumar Vivek Mitra 2012-06-08 05:03:54

La première est une fonction qui accepte un paramètre qui doit être une liste d'éléments de E type.

le deuxième type d'exemple n'est pas défini

List<?> list

ainsi vous pouvez passer la liste de n'importe quel type d'objets.

1
répondu Pramod Kumar 2012-06-08 05:21:32

Liste comme un type de paramètre dit que le paramètre doit être une liste d'éléments avec n'importe quel type d'objet. En outre, vous pouvez lier le paramètre E pour déclarer des références à la liste des éléments à l'intérieur du corps de la fonction.

la liste en tant que type de paramètre a la même sémantique, sauf qu'il n'y a pas d'autre moyen de déclarer les références aux éléments de la liste que d'utiliser Object . D'autres messages donnent des différences subtiles supplémentaires.

1
répondu Gene 2018-06-07 13:48:58

j'explique habituellement la différence entre < E > et < ? > par comparaison avec les quantifications logiques, c'est-à-dire la quantification universelle et existentielle.

  • correspond à " forall E, ..."
  • correspond à "il existe quelque chose(indiqué par ) tel que ...."

par conséquent, la déclaration de méthode générique suivante signifie que, pour tout type de classe E , nous définissons funct1

public static <E> void funct1  (List<E>; list1) {

}

la déclaration de méthode générique suivante signifie que, pour une classe existante indiquée par < ? >, nous définissons funct2 .

public static void funct2(List<?> list) {

}
1
répondu user3509406 2018-07-16 10:54:36

(depuis votre édition) ces deux signatures de fonction ont le même effet à l'extérieur du code -- ils prennent tous les deux n'importe quel List comme argument. Un générique est équivalent à un paramètre de type qui est utilisé qu'une seule fois.

0
répondu newacct 2012-06-08 07:28:38

en plus de ces différences mentionnées ci-dessus, il y a aussi une différence supplémentaire: vous pouvez explicitement définir les arguments de type pour l'appel de la méthode générique:

List<Apple> apples = ...
ClassName.<Banana>funct2(apples); // for some reason the compiler seems to be ok
                               // with type parameters, even though the method has none

ClassName.<Banana>funct1(apples); // compiler error: incompatible types: List<Apple>
                                  //                 cannot be converted to List<Banana>

( ClassName est le nom de la classe contenant les méthodes.)

0
répondu fabian 2015-05-24 10:32:08