achingfingers
achingfingers

Reputation: 1936

Add subclass to wildcard-typed generic collection in java

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

Answers (2)

Luiggi Mendoza
Luiggi Mendoza

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

rgettman
rgettman

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

Related Questions