Quelle est la différence entre la Collecte et la Collecte

je suis principalement un développeur C# et j'enseignais les Structures de données à mon ami et ils utilisent Java dans leur université et j'ai vu une telle expression en Java:

void printCollection(Collection<?> c) {
    for (Object e : c) {
        System.out.println(e);
    }
}

je n'ai pas vu une telle chose en C# donc je me demande quelle est la différence entre Collection<T> et Collection<?> en Java?

void printCollection(Collection<T> c) {
    for (Object e : c) {
        System.out.println(e);
    }
}

je pense qu'il aurait pu être écrit de la manière ci-dessus. Le type de la documentation comparait Collection<Object> et Collection<T> si.

Exemples sont tirés de http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html

23
demandé sur Yogesh Umesh Vaity 2012-05-28 02:22:54

4 réponses

Collection<?> est une collection de type inconnu paramètre.

autant Que l'appelant, il n'y a pas de différence entre

void printCollection(Collection<?> c) { ... }

et

<T> void printCollection(Collection<T> c) { ... }

cependant, ce dernier permet à l'implémentation de se référer au paramètre type de la collection et est donc souvent préféré.

L'ancienne syntaxe existe parce qu'il n'est pas toujours possible d'introduire un paramètre de type à la portée appropriée. Par exemple, considérer:

List<Set<?>> sets = new ArrayList<>();
sets.add(new HashSet<String>());
sets.add(new HashSet<Integer>());

si je devais remplacer ? par un paramètre de type T, tous les jeux sets serait limité au même type de Composant, c'est-à-dire que je ne peux plus mettre des ensembles ayant des types d'éléments différents dans la même liste, comme le prouve la tentative suivante:

class C<T extends String> {
    List<Set<T>> sets = new ArrayList<>();

    public C() {
        sets.add(new HashSet<String>()); // does not compile
        sets.add(new HashSet<Integer>()); // does not compile
    }
}
25
répondu meriton 2013-11-02 10:06:11

La déclaration Collection<?> (prononcé "collection de l'inconnu") est une collection dont le type de l'élément correspond à rien, alors que Collection<T> signifie une collection de type T.

comme d'habitude Angelika Langer's FAQ sur les génériques a une discussion approfondie sur le sujet, un must-read pour bien comprendre tout sur les génériques en Java, et les caractères génériques illimités (le sujet de cette question) en particulier. Citant la FAQ:

les non-limités générique ressemble " ? "et représente la famille de tous les types. Le caractère sauvage illimité est utilisé comme argument pour les instanciations de types génériques. Le caractère sauvage illimité est utile dans les situations où aucune connaissance de l'argument type d'un type paramétré n'est nécessaire

Pour plus de détails techniques, consultez la section §4.5.1 Type des Arguments et des caractères génériquesSpécification Du Langage Java, qui stipule que:

les arguments de Type peuvent être des types de référence ou des caractères génériques. Les caractères génériques sont utiles dans les situations où seule une connaissance partielle du paramètre type est requise.

19
répondu Óscar López 2012-05-28 01:33:45

Collection<T> vous pourriez faire

void printCollection(Collection<T> c) {
    for (T e : c) {
        System.out.println(e);
    }
}

Collection<?> vous savez seulement que la collection contient des objets.

5
répondu Don Roby 2012-05-27 22:28:57

celui qui utilise le caractère illimité (?) signifie en fait ? extends Object (tout ce qui s'étend de l'Objet).

ceci, en Java, implique une nature en lecture seule, à savoir, nous sommes autorisés à lire des éléments de la structure générique, mais nous ne sommes pas autorisés à y remettre quoi que ce soit, parce que nous ne pouvons pas être certains du type réel des éléments qu'il contient.

par conséquent, je crois que c'est une approche très valable dans le printCollection méthode en cours de discussion, au moins, jusqu'à ce que nous rencontrons un situation dans laquelle nous devons assumer un type.

S'il fallait choisir entre les deux, je dirais que le second (avec le paramètre de type T) est une approche plus propre parce qu'on peut au moins supposer que la collection a un certain type T, et qui peut s'avérer utile dans certains scénarios.

Par exemple, si la Collection devait être synchronisés, je pourrais simplement faire:

<T> void printCollection(Collection<T> c) {
    List<T> copy = new ArrayList<T>();
    synchronized(c) {
        copy.addAll(c);
    }
    for (T e : copy) {
        System.out.println(e);
    }
}

j'ai très facilement créé une nouvelle collection de type T, et copier tous les éléments de la collection originale dans ce deuxième. Ce que je peux faire, parce que je peux supposer que le type de la collection est T, et non ?.

je pourrais, bien sûr, faire la même chose avec la première méthode (en utilisant le Joker ubounded), mais ce n'est pas si propre, j'ai dû faire des suppositions que le type de la Collection est Objet, et pas ? (qui ne peut pas être valablement utilisé comme argument de type:new ArrayList<?>()).

void printCollection(Collection<?> c) {
    List<Object> copy = new ArrayList<Object>();
    synchronized(c) {
        copy.addAll(c);
    }
    for (Object e : copy) {
        System.out.println(e);
    }
}
5
répondu Edwin Dalorzo 2012-05-28 00:55:06