Add parent object to List<? extends Parent> - Java

1.7k views Asked by At

I am trying to put a subclass object into a List but I am unable to do so because of the compiler error mentioned as a comment. Can someone point out what is the correct way to do this in Java?

public class Animal { }

class Util {

    private Map<Class<? extends Animal>, List<? extends Animal>> animalListMap;

    public void registerAnimal(Class<? extends Animal> animalClass, Animal animalObject) {

        if (animalListMap.containsKey(animalClass)) {
            //Append to the existing List
            List<? extends Animal> animalList = animalListMap.get(animalObject);
            animalList.add(animalObject); //COMPILE ERROR- The method add(capture#3-of ? extends Animal) in the type List<capture#3-of ? extends Animal> is not applicable for the arguments (Animal)
        } else {
            // and the new entry
            List<Animal> vos = new ArrayList<Animal>();
            vos.add(animalObject);
            animalListMap.put(animalClass, vos);
        }
    }
}
4

There are 4 answers

0
user253751 On BEST ANSWER

You cannot add anything to a List<? extends Animal>, ever. List<? extends Animal> means "a list of I-don't-know-what-but-something-that-extends-Animal", which could be a List<Animal> or a List<Cat>.

If you could, this code would compile:


List dogs = new ArrayList();
List animals = dogs;
animals.add(new Cat());
Dog dog = dogs.get(0);

You can, however, change List<? extends Animal> to List<Animal> which seems to be what you want here.

0
Sotirios Delimanolis On

You declare

List<? extends Animal> animalList = animalListMap.get(animalObject);

The ? extends Animal is a wildcard bounded by the Animal class. So animalListMap.get(animalObject); could return a List<Donkey>, List<Mouse>, List<Pikachu>, assuming Donkey, Mouse, and Pikachu were all sub classes of Animal. However, with the wildcard, you are telling the compiler that you don't care what the actual type is as long as it is a sub type of Animal.

Since you don't know what it is, you can't actually add anything (except null) to it. If what you got back was a List<Pikachu>, but animalObject was actually referencing a Donkey object, you would have problems down the line. That's why the compiler won't let this code compile.

If you have a List<Animal>, then you can add any object that has the type or parent type Animal.

4
Taylor On

Because animalList is a list of something that extends animal, but may not be concretely animal. In other words it may be restricted to some subtype of animal, for instance you could have a list of Lion, Tiger or Bear (oh my!).

As well, your code is prone to weirdness, consider the following calling code example:

myUtil.registerAnimal(Zebra.class, new Tiger());
0
Evgeniy Dorofeev On

You have to change this declaration

private Map<Class<? extends Animal>, List<? extends Animal>> animalListMap;

if you intend to add Animals to the List.

List<? extends Animal>> instructs the complier not to allow to add anything but null to that List.