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

Kar*_*och 11 java generics collections

我有一个集合类型:

Collection<A> collecA
Run Code Online (Sandbox Code Playgroud)

我的对象中有一个列表:

List<B> listB
Run Code Online (Sandbox Code Playgroud)

B在哪里延伸A.

class B extends A { ... }
Run Code Online (Sandbox Code Playgroud)

但我不能做到以下几点:

collecA = listB
Run Code Online (Sandbox Code Playgroud)

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

Ber*_*t F 16

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

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!
Run Code Online (Sandbox Code Playgroud)

方法调用collecA.add(new A())看起来没问题,因为collecA是一个包含As 的集合.但是,如果允许上面的赋值,那么我们就会遇到一个问题,因为collecA它实际上是对一个List<B>实例的引用- 我只是添加了A一个只能容纳Bs 的列表!

阿斯克尔还说:

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

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

class B extends A { ... }
List<A> listA;
List<B> listB;
listA = listB;  // still an error, still leads to the same problem
Run Code Online (Sandbox Code Playgroud)

关键是List<A> 变量只能引用List可以保存As的s.但是,一个List<B> 实例无法容纳As.因此,类似的List<A> 变量listA不能被赋予对引用的List<B> 实例的引用listB.

或者更一般地讲:B是的子类,A没有暗示SomeGenericClass<B>是的一个子类SomeGenericClass<A>(JLS§4.10:分型不通过泛型类型延伸:T <: U并不意味着C<T> <: C<U>.)


这个来自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<E> extends Collection<E>;
...
Cage<Lion> lionCage = ...;
Cage<Butterfly> butterflyCage = ...;
Run Code Online (Sandbox Code Playgroud)

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

Cage<Animal> animalCage = ...;
Run Code Online (Sandbox Code Playgroud)

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

animalCage = lionCage;  // compile-time error
animalCage = butterflyCage; // compile-time error
Run Code Online (Sandbox Code Playgroud)

"

  • Bert很容易理解.在尝试理解泛型和继承时,我总是欣赏愚蠢的类比.卡托克应该检查一下. (3认同)
  • @Tamon - 很高兴你(希望其他人)发现它很容易理解.我在理解泛型和继承时遇到了同样的问题(更不用说通用通配符了),所以它采用了一个新的例子,就像在Java泛型教程中一样,在我的脑海中诠释它.我搜索了"java通用铸造动物笼子",以便记住我读到这个类比的确切位置.:-) (2认同)

Boz*_*zho 10

Collection<? extends A> collecA
Run Code Online (Sandbox Code Playgroud)

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


aio*_*obe 5

Java泛型不是协变的.

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

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

想象一下,您可以将List <Integer>分配给List <Number>.然后,以下代码将允许您将不是Integer的内容放入List <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!
Run Code Online (Sandbox Code Playgroud)