Since the list is of type <? extends Animal>, so it can be any animal. It can be a Dog, a human or a Cat. So the compiler wont allow you to add anything to this list. You cannot add anything to this list by any means(of course you can do that by using legacy code).
The way that i see that: The reference variable is declared as
List<? extends Animal> list
and your code assigns a new ArrayList<Cat>() to it.
it is true that list is currently set to a "Cat" object but the compiler has to behave as though, at "run time" any type of List implementing obejct COULD BE assigned to list that matches the type specified ( <Dog>, <Cat>, <Bird> ). Because of that, the compiler must allow List to accept any of those types (including Animal) but the only way that the compiler can guarantee type safety is to prohibit adding anything at all to the collection.
SCJP - 86% - June 11, 2009
i am not able understand what does it "List<? extends Animal> list = new ArrayList<Cat>();" mean. What I learnt from this is "list can contain any Animal or subtype of Animal." In that sense the statement "list.add(new Cat());" is correct.rt?
Please clarify me.
Joined: Jun 04, 2007
Not quite Suresh, a fine point:
list can not hold an animal or subclass of animal, rather, it can hold a LIST OF animal or subclass of animal.
You see list is of type List so it can hold a reference to a container that implements the List interface. The generic type specification <? extends Animal> says that whatever container list points to can CONTAIN Animal or a subclass of Animal. That said, you can assign a reference to ArrayList<Animal>, Vector<Dog>, or LinkedList<Cat> to the reference variable "list".
Where the problem comes in.... the compiler has to think very generally when it compiles your code. It is true that your specific code is assigning a new ArrayList<Cat> to list. The compiler does not assume that this will be the only thing stored in list at run-time. It has to be prepared to accept ANY type that the generic type says. And THAT could be any of <Animal>, <Dog>, <Cat>, or any other subclass of Animal. Since the compile has no way to know which generic types might be assigned to list, the only way that it can guarantee type safety, is to prohibit any additions to references specified as <? extends ClassName>. If list ever got assigned an ArrayList<Dog> you would not want to add a Cat to it. Since the run-time environment (JVM) has no way to check/limit the type of Object added at run time, the compiler must do the type enforcement itself and the only way that it can do that is to forbid you from adding anything to it.
Note that: if List were List<? super Animal> the add would work. THAT generic type guarantees that whatever List is assigned WILL be of a type that will at least hold Animal and, if it can hold Animal then it can hold any subclass of Animal, so the compiler will allow that.
Read this and think about it and see if it looks a little more clear.