如何将继承对象的列表转换为Java中的对象集合?
我有一个集合类型:如何将继承对象的列表转换为Java中的对象集合?
Collection<A> collecA
而且我已经在我的对象列表:
List<B> listB
其中B是延伸的
class B extends A { ... }
但我不能请执行以下操作:
collecA = listB
我不明白为什么集合是由List实现的。
让我们假设一个时刻,你可以做你的描述:
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
秒。但是,实例不能容纳A
s。因此,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
“
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!
Collection<? extends A> collecA
这修复它。问题不是List extends Collection
,而是泛型类型。
您可以指定清单< 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 [],并且赋值是合法的。
好易理解的解释伯特我一直赞赏愚蠢试图了解泛型和继承类比时,应Kartoch检查一下 – tgai 2010-05-02 21:34:35
@Tamon - 很高兴你(希望其他人)发现它很容易理解,我对理解泛型和继承有同样的问题(更不用说通用通配符),所以它采用了一个新的例子,就像Java泛型教程在我的脑海中将它融入其中我搜索了'java generic cast animal cage'来记住我在哪里阅读这个比喻。:-) – 2010-05-02 22:16:41
确实很好的解释... – Kartoch 2010-05-03 10:39:06