J'ai quelques questions sur les caractères génériques génériques en Java:
Quelle est la différence entre
List<? extends T>
etList<? super T>
?Qu'est-ce qu'un joker borné et qu'est-ce qu'un joker illimité?
J'ai quelques questions sur les caractères génériques génériques en Java:
Quelle est la différence entre List<? extends T>
et List<? super T>
?
Qu'est-ce qu'un joker borné et qu'est-ce qu'un joker illimité?
Réponses:
Dans votre première question, <? extends T>
et <? super T>
sont des exemples de caractères génériques délimités. Un joker illimité ressemble <?>
, et signifie essentiellement <? extends Object>
. Cela signifie vaguement que le générique peut être de n'importe quel type. Un caractère générique borné ( <? extends T>
ou <? super T>
) place une restriction sur le type en disant qu'il doit soit étendre un type spécifique ( <? extends T>
est connu comme une limite supérieure), soit doit être un ancêtre d'un type spécifique ( <? super T>
est connu comme une limite inférieure) .
Les didacticiels Java ont de très bonnes explications sur les génériques dans les articles Wildcards et More Fun with Wildcards .
<? super C>
signifierait que votre type est limité à quelque chose ci-dessus C
dans la hiérarchie des types. (Désolé pour la réponse extrêmement tardive. Je suppose que nous n'avons pas eu de notifications de commentaires il y a 2 ans?)
Si vous avez une hiérarchie de classes A, B est une sous-classe de A, et C et D sont tous deux une sous-classe de B comme ci-dessous
class A {}
class B extends A {}
class C extends B {}
class D extends B {}
ensuite
List<? extends A> la;
la = new ArrayList<B>();
la = new ArrayList<C>();
la = new ArrayList<D>();
List<? super B> lb;
lb = new ArrayList<A>(); //fine
lb = new ArrayList<C>(); //will not compile
public void someMethod(List<? extends B> lb) {
B b = lb.get(0); // is fine
lb.add(new C()); //will not compile as we do not know the type of the list, only that it is bounded above by B
}
public void otherMethod(List<? super B> lb) {
B b = lb.get(0); // will not compile as we do not know whether the list is of type B, it may be a List<A> and only contain instances of A
lb.add(new B()); // is fine, as we know that it will be a super type of A
}
Un caractère générique borné est comme ? extends B
si B est un type. Autrement dit, le type est inconnu mais une "borne" peut être placée dessus. Dans ce cas, il est délimité par une classe, qui est une sous-classe de B.
List<? super B>
décrit comme List accepte le type qui est la classe parente de la classe B ? C'est pourquoi C et D ne compilent pas hmm?
Josh Bloch a également une bonne explication sur le moment de l'utiliser super
et extends
dans cette conférence vidéo google io où il mentionne le mnémonique Producer extends
Consumersuper
.
À partir des diapositives de la présentation:
Supposons que vous souhaitiez ajouter des méthodes en bloc à
Stack<E>
void pushAll(Collection<? extends E> src);
- src est un producteur E
void popAll(Collection<? super E> dst);
- dst est un consommateur E
Il peut arriver que vous souhaitiez restreindre les types de types autorisés à être transmis à un paramètre de type. Par exemple, une méthode qui opère sur des nombres peut vouloir uniquement accepter des instances de Number ou de ses sous-classes. C'est à cela que servent les paramètres de type borné.
Collection<? extends MyObject>
signifie qu'il peut accepter tous les objets qui ont une relation IS- A avec MyObject (c'est-à-dire tout objet qui est un type de myObject ou nous pouvons dire tout objet de n'importe quelle sous-classe de MyObject) ou un objet de la classe MyObject.
Par exemple:
class MyObject {}
class YourObject extends MyObject{}
class OurObject extends MyObject{}
Ensuite,
Collection<? extends MyObject> myObject;
n'acceptera que MyObject ou les enfants de MyObject (c'est-à-dire tout objet de type OurObject ou YourObject ou MyObject, mais pas tout objet de superclasse de MyObject).
En général,
Si une structure contient des éléments avec un type de formulaire
? extends E
, nous pouvons extraire des éléments de la structure, mais nous ne pouvons pas mettre d'éléments dans la structure
List<Integer> ints = new ArrayList<Integer>();
ints.add(1);
ints.add(2);
List<? extends Number> nums = ints;
nums.add(3.14); // compile-time error
assert ints.toString().equals("[1, 2, 3.14]");
Pour mettre des éléments dans la structure, nous avons besoin d'un autre type de caractère générique appelé Wildcards with super
,
List<Object> objs = Arrays.<Object>asList(2, 3.14, "four");
List<Integer> ints = Arrays.asList(5, 6);
Collections.copy(objs, ints);
assert objs.toString().equals("[5, 6, four]");
public static <T> void copy(List<? super T> dst, List<? extends T> src) {
for (int i = 0; i < src.size(); i++) {
dst.set(i, src.get(i));
}
}
Des caractères génériques génériques sont créés pour rendre les méthodes qui fonctionnent sur Collection plus réutilisables.
Par exemple, si une méthode a un paramètre List<A>
, nous ne pouvons donner List<A>
qu'à cette méthode. C'est un gaspillage pour la fonction de cette méthode dans certaines circonstances :
List<A>
, alors nous devrions être autorisés à donner List<A-sub>
à cette méthode. (Parce que A-sub EST un A)List<A>
, alors nous devrions être autorisés à donner List<A-super>
à cette méthode. (Parce que A EST un A-super)