Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is List<Dog> a subclass of List<Animal>? Why are Java generics not implicitly polymorphic?

I'm a bit confused about how Java generics handle inheritance / polymorphism.

Assume the following hierarchy -

Animal (Parent)

Dog - Cat (Children)

So suppose I have a method doSomething(List<Animal> animals). By all the rules of inheritance and polymorphism, I would assume that a List<Dog> is a List<Animal> and a List<Cat> is a List<Animal> - and so either one could be passed to this method. Not so. If I want to achieve this behavior, I have to explicitly tell the method to accept a list of any subclass of Animal by saying doSomething(List<? extends Animal> animals).

I understand that this is Java's behavior. My question is why? Why is polymorphism generally implicit, but when it comes to generics it must be specified?

like image 294
froadie Avatar asked Apr 30 '10 14:04

froadie


1 Answers

No, a List<Dog> is not a List<Animal>. Consider what you can do with a List<Animal> - you can add any animal to it... including a cat. Now, can you logically add a cat to a litter of puppies? Absolutely not.

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

Suddenly you have a very confused cat.

Now, you can't add a Cat to a List<? extends Animal> because you don't know it's a List<Cat>. You can retrieve a value and know that it will be an Animal, but you can't add arbitrary animals. The reverse is true for List<? super Animal> - in that case you can add an Animal to it safely, but you don't know anything about what might be retrieved from it, because it could be a List<Object>.

like image 111
Jon Skeet Avatar answered Oct 14 '22 21:10

Jon Skeet