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
也会起作用,因为Cat
或Animal
的实例是Animal
的任何超类的实例。
List extends Animal>
List extends Animal>
表示List
,其中X
是Animal
的未知子类型。
因此它有方法
void add(X item); X get(int i);
你不能调用add(cat),因为我们不知道Cat是否是X的子类型。由于X
是未知的,我们知道的唯一值是X
的子类型是null
,所以你可以add(null)
但没有别的。
我们可以做Animal a = list.get(i)
,因为该方法返回X
而X
是Animal
的子类型。 所以我们可以调用get(i)
并将返回值视为Animal。
相反, List super Animal>
List super Animal>
表示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只允许您添加作为类型参数给定的类型(或子类型)的对象。 如果你把 extends Animal>
extends Animal>
它意味着列表具有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派生的任何东西传递到此列表中是安全的。 列表以这种方式处理,并允许添加如上所述的对象。 因此它有效。
希望能帮助到你!