如何将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
变量只能引用可以容纳A
的List
。 但是, List
实例无法保存A
s。 因此,像listA
这样的List
变量不能被赋予对listA
引用的List
实例的引用。
或者更一般地说: B
是A
的子类并不意味着SomeGenericClass
是SomeGenericClass
的子类 ( JLS§4.10 : Subtyping 不扩展通用类型: T <: U
并不意味着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 = ...;
这是一个笼子,旨在容纳各种动物, 混合在一起 。 它必须有足够坚固的杆以容纳在狮子中,并且足够紧密地隔开以容纳在蝴蝶中。
...
由于狮子是一种动物(狮子是动物的一种亚型),因此问题就变成了,“狮子笼是一种动物笼吗? Cage
是Cage
的亚型吗?”。 通过动物笼的上述定义,答案必须是“否”。 这太令人惊讶了! 但是当你想到这件事时它是完全合理的:狮子笼不能被认为是留在蝴蝶中,并且蝴蝶笼不能被认为可以容纳狮子。 因此,两个笼子都不能被视为“全动物”笼子:
animalCage = lionCage; // compile-time error animalCage = butterflyCage; // compile-time error
“
Collection extends A> 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 [],并且赋值是合法的。