如何将继承对象列表转换为Java中的对象集合?
我有一个集合类型:
Collection<A> collecA
我的对象中有一个列表:
List<B> listB
其中 B 扩展 A
class B extends A { ... }
但我不能执行以下操作:
collecA = listB
我不明白为什么,因为 Collection 是由 List 实现的。
I've a collection type:
Collection<A> collecA
And I've a list in my object:
List<B> listB
Where B is extending A
class B extends A { ... }
But I can't do the following:
collecA = listB
I can't understand why since Collection is implemented by List.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
让我们假设您可以执行您所描述的操作:
方法调用
collecA.add(new A())
看起来没问题,因为collecA
是一个集合包含
A
。然而,如果允许上述分配,那么我们有一个问题是因为
collecA
实际上是对List
实例的引用 - 我只是将
A
添加到只能容纳B
的列表中!阿斯克还说:
Collection 是 List 的超类并不重要。即使您使用了两个列表,此分配也是非法的。
关键是
List
变量只能引用可以容纳A
的List
s。但是,List
实例不能容纳A
。因此,像listA
这样的List
变量 不能分配对
List
的引用< em>实例由listB
引用。或者更一般地说:
B
是A
的子类> 是否不暗示SomeGenericClass
是SomeGenericClass
的子类 (JLS §4.10:子类型不通过泛型类型扩展:< code>T <: U 并不意味着C<: C
。)这是来自 的示例/类比Java 泛型教程帮助我理解了这一点:
“如果你想到有形的物体——你可以实际想象的东西——比如笼子,那么理解为什么会变得容易得多:
但是“动物笼子”呢?英语是模棱两可的,所以准确地说,让我们假设我们正在谈论一个“全动物笼子”:
这是一个设计用于容纳各种动物的笼子,混合在一起。栏杆的强度足以容纳狮子,间距足够小,足以容纳蝴蝶。
...
由于狮子是一种动物(狮子是动物的子类型),因此问题就变成了,“狮子笼是动物笼子的一种吗?
Cage
是的子类型吗?” >笼子<动物>
?”。根据上述动物笼的定义,答案一定是“否”。这太令人惊讶了!但仔细想想,这是完全有道理的:不能假设狮子笼里关着蝴蝶,也不能假设蝴蝶笼里关着狮子。因此,这两个笼子都不能被视为“全动物”笼子:“
Let's assume for a moment you could do what you describe:
The method call
collecA.add(new A())
appears okay sincecollecA
is a collectionthat holds
A
s. However, if the above assignment were allowed, then we have aproblem because
collecA
is really reference to aList<B>
instance - I justadded an
A
into a list that can only holdB
s!Asker also said:
It doesn't matter that Collection is a superclass of List. This assignment is illegal even if you used two lists.
The key is that the
List<A>
variable can reference onlyList
s that can holdA
s. However, aList<B>
instance cannot holdA
s. Therefore, aList<A>
variable likelistA
cannot be assigned a reference to aList<B>
instance referred to bylistB
.Or more generally speaking:
B
being a subclass ofA
does not imply thatSomeGenericClass<B>
is a subclass ofSomeGenericClass<A>
(JLS §4.10: Subtyping does not extend through generic types:T <: U
does not imply thatC<T> <: C<U>
.)It was this example/analogy from the Java Generics Tutorial that helped me understand this:
"Understanding why becomes much easier if you think of tangible objects — things you can actually picture — such as a cage:
But what about an "animal cage"? English is ambiguous, so to be precise let's assume we're talking about an "all-animal cage":
This is a cage designed to hold all kinds of animals, mixed together. It must have bars strong enough to hold in the lions, and spaced closely enough to hold in the butterflies.
...
Since a lion is a kind of animal (Lion is a subtype of Animal), the question then becomes, "Is a lion cage a kind of animal cage? Is
Cage<Lion>
a subtype ofCage<Animal>
?". By the above definition of animal cage, the answer must be "no". This is surprising! But it makes perfect sense when you think about it: A lion cage cannot be assumed to keep in butterflies, and a butterfly cage cannot be assumed to hold in lions. Therefore, neither cage can be considered an "all-animal" cage:"
这解决了它。问题不在于
List extends Collection
,而在于泛型类型。This fixes it. The problem is not the
List extends Collection
, but the generic types instead.Java 泛型不是协变的。
请参阅 Java 理论与实践:泛型陷阱 了解更多详细信息。
该页面显示了一个简单的示例,如果它是协变的,则会破坏类型系统:
Java generics are not covariant.
See Java Theory and Practice: Generics Gotchas for further details.
The page shows a simple example that would havoc the type-system if it was covariant:
您可以分配 List到 Collection,但不是 List到集合。
想象一下,如果这是可能的,会发生什么:
如您所见,我们通过将具体类型 A 的实例添加到本应仅包含类型 B(或后代)对象的集合中,“欺骗”了泛型类型系统。
因此,执行隐式转换为 B 的最后一行失败并出现 ClassCastException。有什么问题吗?编译器无法保证类型安全,这违反了 Java 泛型原则之一。
因此,已决定将List添加到列表B中。是集合,但不是列表; (或集合)。
作为旁注,有趣的是,数组不遵循相同的规则:String[] 是一个 Object[],并且赋值是合法的。
You can assign List<B> to Collection<B>, but not List<B> to Collection<A>.
Imagine what would happen if this were possible:
As you see, we "fooled" the generics type system, by adding an instance of concrete type A to a collection that was supposed to have only objects of type B (or descendants).
As a consequence, the last line which performs an implicit cast to B fails with a ClassCastException. What's wrong with it? The compiler can't guarantee type safety, and that's against one of the Java generics principles.
Therefore, it has been decided that List<B> is Collection<B>, but NOT List<A> (or Collection<A>).
As a side comment, it is interesting to note that arrays don't follow the same rules: String[] is an Object[], and assignments are legal.