Java Generics - 将子类列表分配给超类列表

时间:2011-06-07 05:15:00

标签: java generics

我有一个关于将子类列表分配给超类列表的基本问题。

所以我有以下内容:

Class B extends A;

List <B> bList = new ArrayList<B>();
List <A> aList = bList; 

为什么最后一次分配失败?对不起新手问题

7 个答案:

答案 0 :(得分:9)

当您声明类型A的项目列表时,只能在列表中添加或删除类型A的项目。如果需要包含A的子类,请使用通用通配符? extends A来表示。因此,您的代码应为:

List <? extends A> aList = bList; 

答案 1 :(得分:9)

为了解释这一点,让我用“整数”替换“B”,用“数字”替换“A”。这只是为了让它更容易解释。

Class Integer extends Number;

List <Integer> iList = new ArrayList<Integer>();
List <Number> nList = iList // will fail

这会失败的原因是因为nList可以取任何数字 - 它可以取整数,它可以取Double,或者就任何子类的Number而言。但是,对于iList,情况并非如此。您不能将Double添加到iList,因为它只接受Integer及其子类。希望这有助于向您解释。

答案 2 :(得分:2)

List<B>不是List<A>

通过示例:假设您有class B1 extends A{}class B2 extends A{} 然后(如果你能做到这一点:

List<B1> b1 = new AList<B1>();
List<A> a = b1;

List<B2> b2 = new AList<B2>();

根据假设,你应该能够做到     a.add(新B2()) 但这是错误的。

如果您尝试使用arrays而不是列表来尝试相同的操作,它将在运行时编译并抛出异常。

我们说数组是协变,而泛型是不变的

要使代码编译,你就有了它:

List<? extends A> a = b;

这表示a是A的某些子类型的列表。但是你不知道哪一个。因此你不能做a.put(X)

答案 3 :(得分:1)

List<B>List<A>invariant类型。您需要的是covariant类型。在这种情况下,它是List<? extends A>

答案 4 :(得分:0)

因为泛型是严格类型安全

你可以拥有

List<? extends A> aList = bList;

它说aList可以保存任何类型的列表A

答案 5 :(得分:0)

因为List<B>没有延伸List<A>。例如,Integer扩展NumberLong也扩展List<Number>。因此Integer可以包含LongList<Integer>。因此,如果您将List<Number>分配给Long,则可以将List<? super B> superB; 添加到整数列表中。

您可以声明

aList=bList

这将允许分配包含B及其超类的任何列表的superB。 但这与你的案例List<? extends A> extendsA; 不一样。

    List<? super Integer> superA;
    superA = new ArrayList<Number>();

    List<? extends Number> extendsNumber;
    extendsNumber = new ArrayList<Integer>();

实施例

{{1}}

答案 6 :(得分:0)

乍一看,你可能会认为

Class B extends A;

List <B> bList = new ArrayList<B>();
List <A> aList = bList;

应该有效,当您想象实际使用这些列表时问题是显而易见的:

A something = new A();
aList.add( something ); // Should work because aList is a list of A's

aList已分配给bList,因此应与

相同
bList.add( something ); // Here's the problem

bList.add()需要BsomethingA,而A不是B

这就是为什么泛型应该(并且是)严格类型安全的原因。