java通用和外卡

在javagenerics中我理解了外卡,超级和扩展的含义是什么,但是没有得到为什么不允许我添加任何内容,为什么允许我在层次结构中添加SomeType,但不在层次结构中的上面?

class Animal {} class Cat extends Animal{} 

下面的方法可以采取动物或动物的子列表即猫,但没有别的和我不允许添加任何东西,如果尝试添加,编译器阻止我为什么?

 void addAminal(List aList){ aList.add(new Cat()); // compiler error aList.add(new Animal()); // compiler error } 

现在下面的方法可以采用Animal的任何列表或者任何超类型的Animal,但是没有子类型的Animal,我可以在Animal或者层次结构中添加更低的对象,所以当我尝试添加Object时,编译器会抱怨为什么?

 void addAnimal(List aList){ aList.add(new Animal()); // no error aList.add(new Cat()); // no error aList.add(new Object()); // compiler error why ? } 

谢谢Arya

假设您定义了一个新类:

 class Tabby extends Cat {} 

然后你做了以下事情:

 List aList = new ArrayList(); addAnimal(aList); 

毫无疑问,这个列表不应该有一个Animal或者一个不是Tabby的Cat,但如果编译器没有标记错误,那就是你所拥有的。

原因是,我已经指定了addAnimal来获取扩展Animal的内容列表,但这些内容可能具有很高的限制性。 但是,这会编译:

 void addAnimal(List aList){ aList.add(new Cat()); // OK aList.add(new Animal()); // OK } 

使用super也会起作用,因为CatAnimal的实例是Animal的任何超类的实例。

List List表示List ,其中XAnimal的未知子类型。

因此它有方法

 void add(X item); X get(int i); 

你不能调用add(cat),因为我们不知道Cat是否是X的子类型。由于X是未知的,我们知道的唯一值是X的子类型是null ,所以你可以add(null)但没有别的。

我们可以做Animal a = list.get(i) ,因为该方法返回XXAnimal的子类型。 所以我们可以调用get(i)并将返回值视为Animal。

相反, List List表示List ,其中Y是未知的超级Animal类型。 现在我们可以调用add(cat) ,因为Cat是Animal的子类型,Animal是Y的子类型,因此Cat是Y的子类型, add(Y)接受Cat。 另一方面, Animal a = list.get(0)现在不起作用,因为Animal不是返回类型Y的超类型; 唯一已知的超类型Y是Object,所以我们所能做的就是Object o = list.get(0)

generics只允许您添加作为类型参数给定的类型(或子类型)的对象。 如果你把 它意味着列表具有SOME类型,它是动物的子类。 既然您正在尝试添加Cat,那么您必须确保它确实是Cats的列表,而不是Dogs的列表。
基本上,当你使用通配符时,你将无法将新项目添加到这样的列表中(注意:我没有完整的知识,这可能不完全正确,但它看起来像这样。如果我是,请原谅我错误)

如果您希望能够将任何Animal添加到列表中,只需使用List

好吧,当你说ArrayList <? 扩展Animal>你指定这个列表将包含任何特定类型(作为?指特定/确定类型),类型为Animal或从Animalinheritance的任何东西,但确定的东西。 所以最终,由于generics是用Eraser概念实现的(它通过非generics上限替换程序中的每个generics类型),这个列表应该包含一个特定的类型,但由于(<?extends Animal>)你不要我不知道具体是哪种类型。 因此,即使类型inheritance自Animal,也不允许添加。

但是当你说ArrayList <? super Animal>,它表示arraylist包含派生自Animal的特定类型,即base或super类型为Animal的对象。 因此,将Animal或从Animal派生的任何东西传递到此列表中是安全的。 列表以这种方式处理,并允许添加如上所述的对象。 因此它有效。

希望能帮助到你!