2010-04-04 18 views
35

J'essaie juste de comprendre le mot-clé extends dans Java Generics.Génériques: Liste <? extends Animal> est identique à Liste <Animal>?

List<? extends Animal> signifie que nous pouvons farcir tout objet dans le List qui EST AAnimal

alors ne sera pas le dire aussi suivant la même chose:

List<Animal> 

que quelqu'un peut me aider à connaître la différence entre les deux ci-dessus? Pour moi extends juste un son redondant ici.

Merci!

Répondre

58

List<Dog> est un sous-type de List<? extends Animal>, mais pas un sous-type de List<Animal>. Pourquoi un n'est pas un sous-type de List<Animal>? Prenons l'exemple suivant:

void mySub(List<Animal> myList) { 
    myList.add(new Cat()); 
} 

Si vous avez été autorisé à passer un List<Dog> à cette fonction, vous obtiendrez une erreur d'exécution.


EDIT: Maintenant, si nous utilisons List<? extends Animal> à la place, ce qui se passera:

void mySub(List<? extends Animal> myList) { 
    myList.add(new Cat());  // compile error here 
    Animal a = myList.get(0); // works fine 
} 

Vous pouvez passer un List<Dog> à cette fonction, mais le compilateur se rend compte que l'ajout de quelque chose à la liste pourrait vous causer des ennuis. Si vous utilisez super au lieu de extends (vous permettant de passer un List<LifeForm>), il est l'inverse.

void mySub(List<? super Animal> myList) { 
    myList.add(new Cat());  // works fine 
    Animal a = myList.get(0); // compile error here, since the list entry could be a Plant 
} 

La théorie sous-jacente est Co- and Contravariance.

+4

+1 Pour le lien wikipedia. – helpermethod

+0

Dans votre premier exemple, vous obtiendrez une erreur de compilateur plutôt qu'une erreur d'exécution si vous passez une liste à une liste

+1

@DonLi: En effet. C'est pourquoi j'utilise le [second conditionnel] (https://en.wikipedia.org/wiki/English_conditional_sentences#Second_conditional): * "Si vous ** avez été autorisé ** ..." *, c'est-à-dire dans le scénario hypothétique que le compilateur considéré comme 'Liste ' pour être un sous-type de 'Liste '. – Heinzi

16

Il n'est pas. List<Animal> indique que la valeur affectée à cette variable doit être "type" List<Animal>. Cela ne signifie cependant pas qu'il ne doit y avoir que des objets Animal, il peut aussi y avoir des sous-classes.

List<Number> l = new ArrayList<Number>(); 
l.add(4); // autoboxing to Integer 
l.add(6.7); // autoboxing to Double 

Vous utilisez la List<? extends Number> construction si vous êtes intérêt dans une liste qui a Number objets, mais l'objet de la liste elle-même n'a pas besoin d'être de type List<Number> mais peut toute autre liste des sous-classes (comme List<Integer>).

Ceci est quelque fois utilisé pour les arguments de méthode pour dire « Je veux une liste de Numbers, mais je ne me soucie pas si elle est juste List<Number>, il peut être un List<Double> trop ». Cela évite des conversions bizarres si vous avez une liste de certaines sous-classes, mais la méthode attend une liste de baseclass.

public void doSomethingWith(List<Number> l) { 
    ... 
} 

List<Double> d = new ArrayList<Double>(); 
doSomethingWith(d); // not working 

Ce ne fonctionne pas comme vous attend List<Number>, pas List<Double>.Mais si vous avez écrit List<? extends Number>, vous pouvez passer List<Double> objets même s'ils ne sont pas List<Number> objets.

public void doSomethingWith(List<? extends Number> l) { 
    ... 
} 

List<Double> d = new ArrayList<Double>(); 
doSomethingWith(d); // works 

Note: Toute cette substance est sans rapport avec l'héritage des objets dans la liste elle-même. Vous pouvez toujours ajouter des objets Double et Integer dans une liste List<Number>, avec ou sans ? extends.

+0

hmmm .. l'obtenir. Bonne explication – peakit

35

Je vois que vous avez déjà accepté une réponse, mais je voudrais juste ajouter mon point de vue, car je pense que je peux être utile ici. La différence entre List<Animal> et List<? extends Animal> est la suivante.


Avec List<Animal>, vous savez ce que vous avez est certainement une liste des animaux. Il n'est pas nécessaire que tous soient exactement 'Animal' - ils pourraient aussi être des types dérivés. Par exemple, si vous avez une liste d'animaux, il est logique qu'un couple puisse être des chèvres, et certains d'entre eux des chats, etc - non?

Par exemple ceci est tout à fait valable:

List<Animal> aL= new List<Animal>(); 
aL.add(new Goat()); 
aL.add(new Cat()); 
Animal a = aL.peek(); 
a.walk(); // assuming walk is a method within Animal 

Bien sûr, ce qui suit ne pas valable:

aL.peek().meow(); // we can't do this, as it's not guaranteed that aL.peek() will be a Cat 

Avec List<? extends Animal>, vous faites une déclaration au sujet le type de liste vous avez affaire.

Par exemple:

List<? extends Animal> L; 

Ceci est en fait pas une déclaration du type d'objet L peut tenir. C'est une déclaration sur les types de listes que L peut référencer.

Par exemple, nous pourrions faire ceci:

L = aL; // remember aL is a List of Animals 

Mais maintenant tout le compilateur sait L est qu'il est une Liste des [animaux ou un sous-type d'animal] s

Alors maintenant, ce qui suit est pas valide:

L.add(new Animal()); // throws a compiletime error 

Parce que pour tout ce que nous savons, l pourrait être une référence à la liste des chèvres - à des Wh Je ne peux pas ajouter un animal.

Voici pourquoi:

List<Goat> gL = new List<Goat>(); // fine 
gL.add(new Goat()); // fine 
gL.add(new Animal()); // compiletime error 

Dans ce qui précède, nous essayons de jeter un animal comme une chèvre. Ça ne marche pas, parce que si après cela nous essayions de faire de cet Animal un 'headbutt', comme une chèvre? Nous ne savons pas nécessairement que l'animal peut le faire.

+4

+1 pour "Ce n'est en fait pas une déclaration du type d'objet que L peut contenir, c'est une déclaration sur les types de listes que L peut référencer." – Heinzi

+0

et pour la même raison que vous ne pouvez pas faire 'L.add (new Goat())' coz L pourrait être référençant à une liste de chiens auxquels vous ne pouvez pas ajouter Goat à :) – Tarun

+0

heureux que je descends ... Merci pour l'explication.. –