我正在尝试将子类对象放入List中,但由于作为注释提到的编译器错误,我无法这样做。有人可以指出在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);
}
}
}
答案 0 :(得分:3)
您无法向List<? extends Animal>
添加任何内容。 List<? extends Animal>
表示“我不知道什么,但是某些东西 - 扩展动物”的列表,可以是List<Animal>
或List<Cat>
。
如果可以的话,这段代码会编译:
List dogs = new ArrayList(); List animals = dogs; animals.add(new Cat()); Dog dog = dogs.get(0);
但是,您可以将List<? extends Animal>
更改为List<Animal>
,这似乎是您想要的。
答案 1 :(得分:1)
你宣布
List<? extends Animal> animalList = animalListMap.get(animalObject);
? extends Animal
是由Animal
类限定的通配符。因此,animalListMap.get(animalObject);
可以返回List<Donkey>
,List<Mouse>
,List<Pikachu>
,假设Donkey
,Mouse
和Pikachu
都是子类Animal
。但是,使用通配符时,只要它是Animal
的子类型,您就告诉编译器您不关心实际类型是什么。
由于你不知道它是什么,你实际上不能添加任何东西(null
除外)。如果你得到的是List<Pikachu>
,但animalObject
实际上引用了Donkey
对象,那么你就会遇到问题。这就是编译器不会让这段代码编译的原因。
如果您有List<Animal>
,则可以添加具有类型或父类型Animal
的任何对象。
答案 2 :(得分:0)
因为animalList
是一个扩展动物的东西的列表,但可能不是具体的动物。换句话说,它可能仅限于动物的某些亚型,例如你可能有狮子,老虎或熊的名单(哦,我的!)。
同样,您的代码很容易出现怪异,请考虑以下调用代码示例:
myUtil.registerAnimal(Zebra.class, new Tiger());
答案 3 :(得分:0)
您必须更改此声明
private Map<Class<? extends Animal>, List<? extends Animal>> animalListMap;
如果您打算将动物添加到列表中。
List<? extends Animal>>
指示编译器不允许向该列表添加除null之外的任何内容。