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

时间:2021-01-14 15:51:09

I have a basic question regarding assignment of a list of subclass to a list of superclass.

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

So I have something like the following:

所以我有以下内容:

Class B extends A;

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

Why does this last assignment fail? Sorry for the newbie question

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

7 个解决方案

#1


9  

To explain this, let me substitute "B" with Integer and "A" with Number. This is just to make it a little easier to explain.

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

Class Integer extends Number;

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

The reason this would fail is because nList can take any Number -- it can take Integer, it can take Double, or for that matter any subclass of Number. However, this is not true for iList. You cannot add a Double to iList because it accepts only Integer and its subclasses. Hope this helps explain it to you.

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

#2


9  

When you declare a List of items of type A, only items of type A can be added or removed from the List. If you need to include subclasses of A, use the generic wildcard ? extends A to indicate so. Your code should therefore be:

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

List <? extends A> aList = bList; 

#3


2  

List<B> is not List<A>:

列表不是List

Through example: let say you have class B1 extends A{} and class B2 extends A{} then (if you would be able to do that:

通过示例:假设您有B1类扩展A {}而B2类扩展A {}然后(如果您能够这样做:

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

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

by the hypothesis, you should be able to do a.add(new B2()) but this is wrong.

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

If you try the same thing but using arrays instead of lists, it will compile and throw exception in runtime.

如果你尝试相同的事情,但使用数组而不是列表,它将编译并在运行时抛出异常。

We say that arrays are covariant and generics are invariant.

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

to make the code compile you have the wite it:

为了使代码编译,你有它:

List<? extends A> a = b;

this says that a is a list of some subtype of A. _But you don know which one. Because of that you can't do a.put(X)

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

#4


1  

List<B> and List<A> are invariant type. What you need is covariant type. In this case, it is List<? extends A>.

List 和List 是不变类型。你需要的是协变型。在这种情况下,它是List <?扩展A>。

#5


0  

Because generics are strict type safe.

因为泛型是严格的类型安全。

You can have

你可以有

List<? extends A> aList = bList;

It says aList can hold list of any type which is an A

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

#6


0  

Because List<B> does not extend List<A>. For example, Integer extends Number and so does Long. So List<Number> can contain both Integer and Long. So if you assign List<Integer> to List<Number> you will be able to add Long to your list of integers.

因为List 不扩展List 。例如,Integer扩展Number,Long也是如此。所以List 可以包含Integer和Long。因此,如果将List 分配给List ,则可以将Long添加到整数列表中。

You can declare

你可以申报

List<? super B> superB;

And that would allow assignment to superB of any list that contains B and its super classes. But it's not the same as in your case aList=bList.

这将允许分配包含B及其超类的任何列表的superB。但它与你的情况aList = bList不同。

or

要么

List<? extends A> extendsA;

Examples

例子

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

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

#7


0  

While at first glance you might think that

乍一看你可能会想到这一点

Class B extends A;

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

should work, the problem is obvious when you imagine actually using these lists:

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

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

but aList was assigned to bList, so that should be the same as

但是aList被分配给bList,所以它应该是相同的

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

bList.add() takes a B, but something is an A, and an A is not a B!

bList.add()接受B,但是A是A,而A不是B!

And that's why generics should be (and are) strict type safe.

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

#1


9  

To explain this, let me substitute "B" with Integer and "A" with Number. This is just to make it a little easier to explain.

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

Class Integer extends Number;

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

The reason this would fail is because nList can take any Number -- it can take Integer, it can take Double, or for that matter any subclass of Number. However, this is not true for iList. You cannot add a Double to iList because it accepts only Integer and its subclasses. Hope this helps explain it to you.

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

#2


9  

When you declare a List of items of type A, only items of type A can be added or removed from the List. If you need to include subclasses of A, use the generic wildcard ? extends A to indicate so. Your code should therefore be:

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

List <? extends A> aList = bList; 

#3


2  

List<B> is not List<A>:

列表不是List

Through example: let say you have class B1 extends A{} and class B2 extends A{} then (if you would be able to do that:

通过示例:假设您有B1类扩展A {}而B2类扩展A {}然后(如果您能够这样做:

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

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

by the hypothesis, you should be able to do a.add(new B2()) but this is wrong.

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

If you try the same thing but using arrays instead of lists, it will compile and throw exception in runtime.

如果你尝试相同的事情,但使用数组而不是列表,它将编译并在运行时抛出异常。

We say that arrays are covariant and generics are invariant.

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

to make the code compile you have the wite it:

为了使代码编译,你有它:

List<? extends A> a = b;

this says that a is a list of some subtype of A. _But you don know which one. Because of that you can't do a.put(X)

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

#4


1  

List<B> and List<A> are invariant type. What you need is covariant type. In this case, it is List<? extends A>.

List 和List 是不变类型。你需要的是协变型。在这种情况下,它是List <?扩展A>。

#5


0  

Because generics are strict type safe.

因为泛型是严格的类型安全。

You can have

你可以有

List<? extends A> aList = bList;

It says aList can hold list of any type which is an A

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

#6


0  

Because List<B> does not extend List<A>. For example, Integer extends Number and so does Long. So List<Number> can contain both Integer and Long. So if you assign List<Integer> to List<Number> you will be able to add Long to your list of integers.

因为List 不扩展List 。例如,Integer扩展Number,Long也是如此。所以List 可以包含Integer和Long。因此,如果将List 分配给List ,则可以将Long添加到整数列表中。

You can declare

你可以申报

List<? super B> superB;

And that would allow assignment to superB of any list that contains B and its super classes. But it's not the same as in your case aList=bList.

这将允许分配包含B及其超类的任何列表的superB。但它与你的情况aList = bList不同。

or

要么

List<? extends A> extendsA;

Examples

例子

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

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

#7


0  

While at first glance you might think that

乍一看你可能会想到这一点

Class B extends A;

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

should work, the problem is obvious when you imagine actually using these lists:

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

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

but aList was assigned to bList, so that should be the same as

但是aList被分配给bList,所以它应该是相同的

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

bList.add() takes a B, but something is an A, and an A is not a B!

bList.add()接受B,但是A是A,而A不是B!

And that's why generics should be (and are) strict type safe.

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