Reputation: 1936
This is legal:
List<? extends Animal> animals = getMonkeys();
...
List<Monkey> getMonkeys(){
...
}
The following results in a compiler error:
animals.add(new Donkey());
Why? How can I add a subtype legally?
Upvotes: 1
Views: 201
Reputation: 85809
Just declare the list as List<Animal>
. Any object which class extends from Animal
will be able to be inserted there.
Use wildcard in a List<? extends Foo>
when you're traversing the elements of the collection and want/need that the elements in the collection belong to a specific class. For example:
class Animal {
public String getSpecie() {
return "generic animal";
}
}
class Donkey extends Animal {
@Override
public String getSpecie() {
return "generic donkey";
}
}
class Mokney extends Animal {
@Override
public String getSpecie() {
return "generic monkey";
}
}
//some method in an utility class...
//we are declaring that only List<Animal> or List<some class that extends animal> can be passed as argument
public void printSpecies(List<? extends Animal> animalList) {
//we can be sure every element in animalList is an animal always
for (Animal animal : animalList) {
System.out.println(animal.getSpecie());
}
}
//calling the method above...
List<Monkey> monkeyList = ...
printSpecies(monkeyList); //compiles and works
List<Donkey> donkeyList = ...
printSpecies(donkeyList); //compiles and works
List<String> stringList = ...
printSpecies(stringList); //doesn't compile
Upvotes: 3
Reputation: 178363
The compiler doesn't know which subclass the wildcard could be. It could be a List<Fish>
for all it knows. To preserve type safety, the compiler must prevent a call to add
, because one shouldn't be allowed to add a Monkey
to what could be a List<Fish>
.
List<? extends Animal> animals = new ArrayList<Fish>(); // legal
animals.add(new Monkey()); // unsafe; compiler error
animals.add(new Donkey()); // also unsafe; compiler error
To prevent this, you need to eliminate the wildcard in your variable, so that the compiler knows the generic type parameter. A List<Animal>
or a List<Monkey>
(or a List<Donkey>
as the case may be) would allow you to call add
with an argument of something other than null
. If you must call getMonkeys()
, then you must use its return type of List<Monkey>
.
List<Monkey> monkeys = getMonkeys();
monkeys.add(new Monkey());
Upvotes: 4