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?
No, a
List<Dog>is not aList<Animal>. Consider what you can do with aList<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.Suddenly you have a very confused cat.
Now, you can’t add a
Catto aList<? extends Animal>because you don’t know it’s aList<Cat>. You can retrieve a value and know that it will be anAnimal, but you can’t add arbitrary animals. The reverse is true forList<? super Animal>– in that case you can add anAnimalto it safely, but you don’t know anything about what might be retrieved from it, because it could be aList<Object>.