2010-05-02 144 views

回答

15

让我们假设一个时刻,你可以做你的描述:

class B extends A { ... } 

Collection<A> collecA; 
List<B> listB; 

collecA = listB; // normally an error, but lets pretend its allowed 

collecA.add(new A()); // PROBLEM! 

因为collecA是一家集 持有A S中的方法调用collecA.add(new A())似乎还好。但是,如果上述任务被允许,那么我们有 的问题,因为collecA实际上是参考List<B>实例 - 我只是 添加一个A到只能容纳B s!

提问者还表示:

我不明白为什么,因为收藏是通过列表来实现。

集合是List的超类无关紧要。即使您使用了两个列表,此分配也是非法的。

class B extends A { ... } 
List<A> listA; 
List<B> listB; 
listA = listB; // still an error, still leads to the same problem 

的关键是,在List<A>可变只能引用List s表示可容纳A秒。但是,实例不能容纳As。因此,List<A>变量listA不能被指定为参考listB所指的List<B>实例

或者更一般地讲:B是的A一个子类做了暗示SomeGenericClass<B>SomeGenericClass<A>JLS §4.10的子类:亚型不通过泛型类型延伸:T <: U并不意味着C<T> <: C<U>。 )


这是从Java泛型教程这个例子/类比,帮助我理解这一点:

http://java.sun.com/docs/books/tutorial/java/generics/subtyping.html

“理解为什么变得容易得多,如果你认为有形物体的 - 东西,你可以真正的图片 - 如鸟笼,

// A cage is a collection of things, with bars to keep them in. 
interface Cage<E> extends Collection<E>; 
... 
Cage<Lion> lionCage = ...; 
Cage<Butterfly> butterflyCage = ...; 

但是“动物笼子”呢?英语是模糊的,所以要精确假设我们正在谈论的“所有的动物笼”

Cage<Animal> animalCage = ...; 

这是设计容纳各种动物,混合在一起的笼子。它必须有足够坚固的酒吧,以保持在狮子,足够的间隔,以保持在蝴蝶。
...
由于狮子是一种动物(狮子是动物的一种亚型),问题就变成了:“狮子笼是一种动物笼子吗?是Cage<Lion>Cage<Animal>的子类型吗?”。通过动物笼的上述定义,答案必须是“否”。这是令人惊讶的!但是当你考虑它时,它是完全有意义的:一个狮子笼不能被假定为保持在蝴蝶中,并且一个蝴蝶笼不能被假定为拥有狮子。因此,无论笼可考虑“所有动物”鸟笼。

animalCage = lionCage; // compile-time error 
animalCage = butterflyCage; // compile-time error 

+3

好易理解的解释伯特我一直赞赏愚蠢试图了解泛型和继承类比时,应Kartoch检查一下 – tgai 2010-05-02 21:34:35

+2

@Tamon - 很高兴你(希望其他人)发现它很容易理解,我对理解泛型和继承有同样的问题(更不用说通用通配符),所以它采用了一个新的例子,就像Java泛型教程在我的脑海中将它融入其中我搜索了'java generic cast animal cage'来记住我在哪里阅读这个比喻。:-) – 2010-05-02 22:16:41

+0

确实很好的解释... – Kartoch 2010-05-03 10:39:06

5

Java泛型不是covariant

查看Java Theory and Practice: Generics Gotchas了解更多详情。

的页面显示了一个简单的例子,将严重破坏类型系统,如果它是协:

想象一下,你可以一个列表<整数>分配给一个列表<号码>。然后将下面的代码将让你把东西,是不是一个Integer放入名单<整数>:

List<Integer> li = new ArrayList<Integer>(); 
List<Number> ln = li; // illegal 
ln.add(new Float(3.1415)); // ERROR: Adds a float to li, which is a list of Integers! 
8
Collection<? extends A> collecA 

这修复它。问题不是List extends Collection,而是泛型类型。

1

您可以指定清单< B>收集< B>,但不是列表< B>收集< A>。

试想一下,如果这是可能会发生什么:

List<B> = new ArrayList<B>(); 
Collection<A> collecA = listB; //Assume that this line compiles 
collecA.add(new A()); 
B item = listB.get(0); //ClassCastException! 

正如你看到的,我们“上当”的泛型类型的系统,通过增加具体类型的实例,这应该只是有一个集合类型B(或后代)的对象。 因此,对B执行隐式转换的最后一行失败,并带有ClassCastException。它出什么问题了?编译器不能保证类型安全,这是违反Java泛型原则之一的。

因此,已决定列表< B>是类别< B>,而不是列出< A>(或集合< A>)。

作为一个侧面评论,有趣的是,数组并没有遵循相同的规则:String [] 一个Object [],并且赋值是合法的。

相关问题