2008-10-30 5 views
89

J'ai quelques questions sur les caractères génériques génériques en Java:Java Generics (Wildcards)

  1. Quelle est la différence entre List<? extends T> et List<? super T>?

  2. Qu'est-ce qu'un caractère générique délimité et qu'est-ce qu'un caractère générique non borné?

+0

Dans le cas où (http://stackoverflow.com/users/970122/ted-gao) [réponse] [Ted Gao] (http://stackoverflow.com/a/9446233/2476755) est supprimée (puisqu'il s'agit d'un lien uniquement), voici le [blog] (http://ted-gao.blogspot.com/search/label/Java%20Generics) auquel il est lié . – royhowie

Répondre

104

Dans votre première question, <? extends T> et <? super T> sont des exemples de caractères génériques bornés. Un caractère générique illimité ressemble à <?>, et signifie essentiellement . Cela signifie vaguement que le générique peut être de n'importe quel type. Un caractère générique délimité (<? 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), ou doit être un ancêtre d'un type spécifique (<? super T> est connu comme une borne inférieure).

Les tutoriels Java ont quelques très bonnes explications des génériques dans les articles Wildcards et More Fun with Wildcards.

+0

Juste pour le faire correctement, si A est faux? –

+0

Si A pour limiter vos choix à A ou B. –

+0

et en cela cas si je dis quelle serait la différence? –

42

Si vous avez une hiérarchie de classes A, B est une sous-classe de A et C et D les deux sont sous-classe de B comme ci-dessous

class A {} 
class B extends A {} 
class C extends B {} 
class D extends B {} 

Puis

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 où B est un certain type. C'est-à-dire que le type est inconnu mais qu'un "bound" peut être placé dessus. Dans ce cas, il est délimité par une classe, qui est une sous-classe de B.

+1

+1 pour des exemples! –

+1

grand exemple, merci – Peter

36

Josh Bloch a aussi une bonne explication de quand utiliser super et extends dans ce google io video talk où il mentionne les producteurs extends consommateurs super mnémotechnique .

Des diapositives de présentation:

Supposons que vous voulez ajouter des méthodes en vrac à Stack<E>

void pushAll(Collection<? extends E> src);

- src est un E producteur

void popAll(Collection<? super E> dst);

- dst est un consommateur E

+0

J'ai lu le livre de Bloch, mais je ne vois toujours pas la différence entre les extensions et super dans ce cas particulier. –

+0

Regardez la vidéo, je pense que c'est assez clair. En outre, je pense que vous devriez poser une autre question sur ce "quelle est la différence entre la liste et la liste " où vous obtiendrez plus de réponses. (Si vous le faites, ajoutez un lien ici) – blank

+2

Lits - pourquoi ne pas inclure l'exemple dans cette réponse pour le rendre complet et autonome. Les liens sont éphémères. –

2

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 uniquement accepter des instances de Number ou de ses sous-classes. C'est à ça que servent les paramètres de type bornés.

Collection<? extends MyObject> 

signifie qu'il peut accepter tous les objets qui ont une relation IS- avec MyObject (à savoirn'importe quel objet qui est un type de myObject ou nous pouvons dire n'importe quel 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; 

acceptera seulement MyObject ou les enfants de MyObject (c.-à-tout objet de type OurObject ou YourObject ou MyObject, mais aucun objet de superclasse MyObject).

1

En général,

Si une structure contient des éléments avec un type de forme ? extends E, nous pouvons obtenir des éléments de la structure, mais nous ne pouvons pas mettre é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)); 
     } 
    } 
0

Les 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 que List<A> à cette méthode. Il est une perte pour le funtion de cette méthode dans certaines circonstances:

  1. Si cette méthode ne lit que des objets de List<A>, alors nous devrions être autorisés à donner List<A-sub> à cette méthode. (Parce que A-sub est un A)
  2. Si cette méthode insère uniquement des objets à List<A>, alors nous devrions être autorisés à donner List<A-super> à cette méthode. (Parce que A est un A-super)
0

Par exemple, nous avons la hiérarchie des classes suivantes

objet < - A < - B, C

Vous devez utiliser List <? extends A> (supérieure relié) si vous allez à lire de la liste

Lorsque vous savez que les instances de la collection sont des instances de A ou des sous-classes de A, il est sûr de lire les instances de la collection et de les convertir en instances A.

Vous ne pouvez pas insérer éléments dans la liste, car vous ne savez pas si la liste est tapée à la classe A, B ou C.

Vous devez utiliser List <? super A> (borne inférieure) si vous allez insérer dans la liste

Quand vous savez que la liste est saisi soit A, ou une superclasse de A, il est sûr d'insérer instances de A ou des sous-classes de A (par exemple B ou C) dans la liste.

Vous ne peut pas lire à partir de la liste, sauf si elle place les objets en lecture à l'objet. Les éléments déjà présents dans la liste peuvent être de n'importe quel type qui est soit un A ou une superclasse de A, mais il n'est pas possible de savoir exactement de quelle classe il s'agit.

En savoir plus ici - http://tutorials.jenkov.com/java-generics/wildcards.html