如何将inheritance对象列表转换为Java中的对象集合?

我有一个集合类型:

Collection collecA 

我的对象中有一个列表:

 List listB 

B在哪里延伸A.

 class B extends A { ... } 

但我无法做到以下几点:

 collecA = listB 

我无法理解为什么Collection是由List实现的。

让我们假设您可以做您所描述的内容:

 class B extends A { ... } Collection collecA; List listB; collecA = listB; // normally an error, but lets pretend its allowed collecA.add(new A()); // PROBLEM! 

方法调用collecA.add(new A())看起来没问题,因为collecA是一个包含A的集合。 但是,如果允许上面的赋值,那么我们就会遇到问题,因为collecA是对List实例的引用 – 我只是将A添加到一个只能保存B的列表中!

阿斯克尔还说:

我无法理解为什么Collection是由List实现的。

Collection是List的超类并不重要。 即使您使用了两个列表,此分配也是非法的。

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

关键是List 变量只能引用可以容纳AList 但是, List 实例无法保存A s。 因此,像listA这样的List 变量不能被赋予对listA引用的List 实例的引用。

或者更一般地说: BA的子类并不意味着SomeGenericClassSomeGenericClass的子类 ( JLS§4.10 : Subtyping 不扩展通用类型: T <: U并不意味着C <: C


这是来自Java Generics Tutorial的示例/类比,帮助我理解了这一点:

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 extends Collection; ... Cage lionCage = ...; Cage butterflyCage = ...; 

但是“动物笼子”呢? 英语含糊不清,所以准确地说我们假设我们谈的是“全动物笼子”

 Cage animalCage = ...; 

这是一个笼子,旨在容纳各种动物, 混合在一起 。 它必须有足够坚固的杆以容纳在狮子中,并且足够紧密地隔开以容纳在蝴蝶中。
...
由于狮子是一种动物(狮子是动物的一种亚型),因此问题就变成了,“狮子笼是一种动物笼吗? CageCage的亚型吗?”。 通过动物笼的上述定义,答案必须是“否”。 这太令人惊讶了! 但是当你想到这件事时它是完全合理的:狮子笼不能被认为是留在蝴蝶中,并且蝴蝶笼不能被认为可以容纳狮子。 因此,两个笼子都不能被视为“全动物”笼子:

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

 Collection collecA 

这解决了它。 问题不在于List extends Collection ,而是generics类型。

Javagenerics不是协变的

有关详细信息,请参阅Java Theory and Practice:Generics Gotchas 。

该页面显示了一个简单的例子,如果它是协变的话会破坏类型系统:

想象一下,您可以将List 分配给List 。 然后,以下代码将允许您将不是Integer的内容放入List 中:

 List li = new ArrayList(); List ln = li; // illegal ln.add(new Float(3.1415)); // ERROR: Adds a float to li, which is a list of Integers! 

您可以将List 分配给Collection ,但不能将List 分配给Collection

想象一下如果可能的话会发生什么:

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

如您所见,我们通过向一个应该只包含B类(或后代)对象的集合中添加具体类型A的实例来“欺骗”generics类型系统。 因此,执行隐式强制转换为B的最后一行失败并出现ClassCastException。 它出什么问题了? 编译器不能保证类型安全,这违反了Javagenerics原则之一。

因此,已经确定List 是Collection ,但是NOT List (或Collection )。

作为旁注,有趣的是注意数组不遵循相同的规则:String [] Object [],并且赋值是合法的。