简体   繁体   中英

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?

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());

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> 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM