2011-09-08 145 views
2

在java通用中,我明白通配符是什么,超级和扩展,但没有得到为什么不允许我添加任何东西,为什么允许我在层次结构中添加upto SomeType,但不在层次结构中?java泛型和通配符

class Animal {} 
class Cat extends Animal{} 

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

void addAminal(List<? extends Aminal> aList){ 
     aList.add(new Cat()); // compiler error 
     aList.add(new Animal()); // compiler error 
} 

现在下面的方法可以采取动物或任何超类型动物的任何名单,但动物没有子类型,我可以在层次结构中添加个动物或物体更低,所以当我尝试添加对象,编译器抱怨为什么?

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

感谢 阿里亚

+1

我建议你看看[Java泛型指南](http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf)和其他有关[协变和反变化](http ://stackoverflow.com/questions/2501023/demonstrate-covariance-and-contravariance-in-java)。 – dm3

+0

我不得不承认这是一个干读,但@ dm3链接的Java泛型的PDF有宝贵的信息。它面向那些了解Java基础知识但不太了解泛型的人。换句话说,从这个问题来看,它是为你写的,巴拉特! :-) – corsiKa

+0

参考这里 - http://stackoverflow.com/questions/4343202/difference-between-super-t-and-extends-t-in-java – IsAs

回答

4

假设你定义一个新的类:

class Tabby extends Cat {} 

然后你做了以下内容:

List<Tabby> aList = new ArrayList<Tabby>(); 
addAnimal(aList); 

毫无疑问,这个名单不应该有一个动物甚至是一个不是虎斑猫的猫,但是如果编译器没有fl ag错误,那就是你会有的。

原因是hou've指定addAnimal需要列出一些可以扩展Animal的内容,但是这可能会造成严重的限制。然而,这将汇编:

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

采用super也将工作,因为无论CatAnimal的一个实例是Animal任何父类的实例。

+0

感谢您的答复泰德。我的疑问是List <?延伸Aminal>将是动物或动物亚型的列表,因此它应该完美地发现将动物或亚类动物添加到列表<?扩展Aminal>,因为我们可以使用列表 l = new ArrayList (); l.add(new Animal()); l.add(new Cat()),这个工作,所以当它是List <?延伸Aminal>为什么它不起作用? – Kabeer

+0

它不工作,因为'List <?扩展动物>'不是可以包含动物或动物亚型的列表。它是Animal的一个子类型的列表,它不会接受任何不属于该子类型的子类型。 (特别是,它可能不会接受动物,就像我的第一个例子)。只需使用'List '作为你的方法的正式参数,你就可以走了。 –

0

泛型只允许您添加类型为(或子类型)的对象作为类型参数。如果你输入<? extends Animal>这意味着列表中有一些类型是动物的一个子类。既然您正在尝试添加猫,您必须确定它确实是猫的列表,而不是狗的列表。
基本上,当你使用通配符时,你将无法将新项目添加到这样的列表中(注意:我没有完整的知识,这可能不完全正确,但它看起来像这样。错了)

如果你想能够添加任何动物到列表中,只需使用List<Animal>

+0

感谢您的回复史蒂文。我知道你在说什么。我没有得到的是为什么<?扩展动物>不允许我添加任何东西,该列表可能包含动物或动物的子类型,有什么危害? – Kabeer

+0

它可能不包含“动物或子类型”。它是一个类型的列表(由'?'表示),它是Animal的一个子类。检查Ted Hopp的例子,在那里他尝试使用你的代码将一个Cat添加到Tabbies列表中,这显然是不允许的。 – Steven

1

List<? extends Animal>表示List<X>其中XAnimal的未知亚型。

因此它具有

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

你不能叫加(猫),因为我们不知道猫是X的一个亚型由于X不明,唯一的价值,我们知道方法

X的子类型是 null,所以你可以 add(null)但没有别的。

我们可以做Animal a = list.get(i),因为该方法返回XXAnimal的子类型。因此,我们可以拨打get(i)并将回报值视为动物。

相反,List<? super Animal>意味着List<Y>其中Y是一个未知的超级类型Animal。现在我们可以拨打add(cat),因为Cat是动物的一个亚型,动物是Y的亚型,因此Cat是Y的亚型,而add(Y)接受Cat。另一方面,Animal a = list.get(0)现在不起作用,因为Animal不是返回类型的超类型Y; Y唯一已知的超类型是Object,所以我们所能做的只是Object o = list.get(0)

0

嗯,当你说ArrayList <?扩展动物>你指定这个列表将包含任何类型的动物或任何从动物继承的特定类型(如?指特定/确定类型),但有些东西确定。因此,最终,由于泛型使用Eraser概念(它用一个非泛型上限替换程序中的每个泛型),因此该列表应该包含特定类型,但由于(<?extends Animal>)你不知道哪个具体的类型是那个。因此,即使类型是从Animal继承的,也不允许添加。

但是当你说ArrayList <?超动物“,这意味着数组列表包含来自动物的特定类型,即,其基数或超类型为动物的物体。因此将动物或动物衍生的任何东西传入此列表是安全的。列表按这种方式处理,并允许按照上述方式添加对象。因此它有效。

希望它有帮助!