In java generic I understood what are the meanign of wild card, super and extends, but didn\'t get why does not allow me to add anything, and why allows me to add upto Som
The generics only allow you to add an object of the type (or a subtype) of the type given as type parameter. If you put <? extends Animal>
it means the list has SOME type that is a subclass of animal. Since you are trying to add a Cat to it, you have to be sure that it is indeed a list of Cats, and not of Dogs.
Basically, when you use a wildcard you will not be able to add new items to such a list (note: I don't have full knowledge and this might not be fully correct, but it seems like this. Forgive me if I'm wrong)
If you want to be able to add any Animal to the list, just use List<Animal>
.
Well, When you say ArrayList< ? extends Animal > you are specifying that this list will contain any specific type (as ? refers to a specific/definite type) that is of type Animal or anything inherited from Animal but something definite. So ultimately, as the generics are implemented with Eraser concept (which replaces every generic type in the program by a non-generic upper bound), this list is supposed to contain a specific type but due to ( < ? extends Animal >) you don't know which specific type is that. And hence you are not allowed to add even though types are inherited from Animal.
But when you say ArrayList< ? super Animal >, it means the arraylist contains specific type derived from Animal that is, objects whose base or super type is Animal. Hence it is safe to pass a Animal or anything derived from Animal into this list. The list is treated that way and it is allowed to add objects as mentioned. And hence it works.
Hope it helps!
Suppose you defined a new class:
class Tabby extends Cat {}
And then you did the following:
List<Tabby> aList = new ArrayList<Tabby>();
addAnimal(aList);
There's no surprise that this list should not have an Animal or even a Cat that isn't a Tabby, yet if the compiler didn't flag the error, that's what you would have.
The reason is that hou've specified addAnimal
to take a list of something that extends Animal, but that something could be highly restrictive. This, however, would compile:
void addAnimal(List<Animal> aList){
aList.add(new Cat()); // OK
aList.add(new Animal()); // OK
}
The use of super
also would work, because an instance of either Cat
or Animal
is an instance of any superclass of Animal
.
List<? extends Animal>
means List<X>
where X
is an unknown subtype of Animal
.
Therefore it has methods
void add(X item);
X get(int i);
You can't call add(cat), because we don't know if Cat is a subtype of X. Since X
is unknown, the only value that we knows is a subtype of X
is null
, so you can add(null)
but nothing else.
We can do Animal a = list.get(i)
, because the method returns X
and X
is a subtype of Animal
. So we can call get(i)
and treat the return value as an Animal.
Conversely, List<? super Animal>
means List<Y>
where Y
is an unknown super type of Animal
. Now we can call add(cat)
, because Cat is a subtype of Animal, Animal is a subtype of Y
, therefore Cat is a subtype of Y
, and add(Y)
accepts a Cat. On the other hand, Animal a = list.get(0)
won't work now, because Animal is not a super type of the return type Y
; the only known super type of Y
is Object, so all we can do is Object o = list.get(0)
.