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