873 votes

Est la liste<Dog> une sous-classe de liste<Animal>? Pourquoi ne sont-ils pas les génériques de Java implicitement polymorphes ?</Animal> </Dog>

Je suis un peu confus sur la façon de Java génériques l'héritage de la poignée / le polymorphisme.

Assumer la hiérarchie suivante -

Animal (Parent)

Chien - Chat (Enfants)

Supposons donc que j'ai une méthode doSomething(List<Animal> animals). Toutes les règles d'héritage et de polymorphisme, je suppose qu'un List<Dog> est un List<Animal> et List<Cat> est un List<Animal> - et l'un ou l'autre ne peut être transmis à cette méthode. De ne pas faire. Si je veux obtenir ce comportement, je dois indiquer explicitement la méthode d'accepter une liste de tout sous-ensemble de l'Animal en disant doSomething(List<? extends Animal> animals).

Je comprends que c'est de Java comportement. Ma question est pourquoi? Pourquoi est-polymorphisme généralement implicite, mais quand il s'agit de génériques, il doit être spécifié?

1025voto

Jon Skeet Points 692016

Non, List<Dog> est pas un List<Animal>. Pensez à ce que vous pouvez faire avec un List<Animal> - vous pouvez ajouter de tout animal de... y compris un chat. Maintenant, pouvez-vous logiquement ajouter un chat à une portée de chiots? Absolument pas.

// Illegal code - because otherwise life would be Bad
List<Dog> dogs = new List<Dog>();
List<Animal> animals = dogs; // Awooga awooga
animals.add(new Cat());
Dog dog = dogs.get(0); // This should be safe, right?

Soudain, vous avez un très confus chat.

Maintenant, vous ne pouvez pas ajouter un Cat d'un List<? extends Animal> parce que vous ne savez pas, c'est un List<Cat>. Vous pouvez récupérer une valeur et de savoir qu'il va être un Animal, mais vous ne pouvez pas ajouter arbitraire des animaux. L'inverse est vrai pour List<? super Animal> - dans ce cas, vous pouvez ajouter un Animal en toute sécurité, mais vous ne savez pas quelque chose sur ce qui peut être récupéré à partir, car il pourrait être un List<Object>.

107voto

Michael Ekstrand Points 12849

Ce que vous cherchez est appelé covariante du type des paramètres. Le problème, c'est qu'ils ne sont pas de type-safe dans le cas général, en particulier pour mutable listes. Supposons que vous avez un List<Dog>, et il est autorisé à fonctionner comme un List<Animal>. Ce qui se passe lorsque vous essayez d'ajouter un Chat à cette List<Animal> ce qui est vraiment un List<Dog>? Automatiquement permettant paramètres de type à être covariantes rompt donc le type de système.

Il serait utile d'ajouter la syntaxe pour permettre le type de spécifier des paramètres comme covariants, ce qui évite l' ? extends Foo dans les déclarations de méthode, mais qui ajoute une complexité supplémentaire.

51voto

Michael Aaron Safyan Points 45071

La raison pour laquelle une Liste<Chien> n'est pas une List<Animal>, c'est que, par exemple, vous pouvez insérer un Chat dans une List<Animal>, mais pas dans une Liste<Chien>... vous pouvez utiliser des caractères génériques pour faire des génériques plus extensible lorsque cela est possible; par exemple, la lecture à partir d'une Liste<Chien> est similaire à la lecture d'une List<Animal> -- mais pas de l'écriture.

Les Génériques du Langage Java et de la Section sur les Generics de Java Tutoriels ont un très bon, explication en profondeur pourquoi certaines choses sont ou ne sont pas polymorphes ou autorisé par des médicaments génériques.

47voto

einpoklum Points 2893

Un point, je pense, devrait être ajouté à ce que d'autres réponses mentionner, c'est que tout

List<Dog> n'est pas- List<Animal> en Java

il est vrai aussi que

Une liste de chiens est-une liste des animaux en anglais

La façon dont les OP de l'intuition qui est tout à fait valable, bien sûr - est de la dernière phrase. Cependant, si l'on applique cette intuition, nous obtenons une langue qui n'est pas Java-esque dans son type de système: Supposons que notre langue ne permettre l'ajout d'un chat à la liste de nos chiens. Ce que cela signifierait? Cela voudrait dire que la liste a de cesse d'être une liste de chiens, et reste simplement une liste d'animaux. Et une liste des mammifères, et une liste de quadrapeds.

Plus généralement, OP intuition se prête vers une langue dans laquelle les opérations sur les objets peuvent changer leur type, ou plutôt, un type d'objet(s) est un (dynamique) en fonction de sa valeur.

38voto

Yishai Points 42417

Je dirais que le point de l'ensemble des Génériques, c'est qu'il ne permet pas que. Envisager la situation avec les tableaux, qui autorisent ce type de covariance:

  Object[] objects = new String[10];
  object[0] = Boolean.FALSE;

Ce code compile bien, mais lève une erreur à l'exécution. Il n'est pas typesafe. Le point de Génériques est à ajouter au moment de la compilation, type de sécurité, sinon vous pouvez simplement coller avec une plaine de classe sans les génériques.

Maintenant, il ya des moments où vous avez besoin d'être plus souple, et c'est ce que l' ? super Classe et ? s'étend de la Classe. L'ancien, c'est quand vous avez besoin de les insérer dans une Collection de type (par exemple), et le dernier est pour quand vous avez besoin de lire, dans un type de manière sécuritaire. Mais le seul moyen de faire les deux en même temps est d'avoir un type spécifique.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X