简体   繁体   English

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

[英]Java Generics — Assigning a list of subclass to a list of superclass

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对不起新手问题

When you declare a List of items of type A, only items of type A can be added or removed from the List.当您声明 A 类型的项目列表时,只能从列表中添加或删除类型 A 的项目。 If you need to include subclasses of A, use the generic wildcard ? extends A如果需要包含 A 的子类,请使用通用通配符? extends A ? extends A to indicate so. ? extends A来表示。 Your code should therefore be:因此,您的代码应为:

List <? extends A> aList = bList; 

To explain this, let me substitute "B" with Integer and "A" with Number.为了解释这一点,让我用 Integer 代替“B”,用数字代替“A”。 This is just to make it a little easier to explain.这只是为了使它更容易解释。

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.这将失败的原因是因为 nList 可以采用任何数字——它可以采用 Integer,它可以采用 Double,或者就此而言,它可以采用 Number 的任何子类。 However, this is not true for iList.但是,对于 iList 来说,情况并非如此。 You cannot add a Double to iList because it accepts only Integer and its subclasses.您不能将 Double 添加到 iList,因为它只接受 Integer 及其子类。 Hope this helps explain it to you.希望这有助于向您解释。

List<B> is not List<A> : List<B>不是List<A>

Through example: let say you have class B1 extends A{} and class B2 extends A{} then (if you would be able to do that:通过示例:假设您有class B1 extends A{}class B2 extends 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(new B2()) 但这是错误的。

If you try the same thing but using arrays instead of lists, it will compile and throw exception in runtime.如果您尝试相同的操作但使用arrays而不是列表,它将在运行时编译并抛出异常。

We say that arrays are covariant and generics are invariant .我们说 arrays 是协变的,而 generics 是不变的。

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.这表示 a 是 A 的某个子类型的列表。_但你不知道是哪一个。 Because of that you can't do a.put(X)因此你不能做a.put(X)

List<B> and List<A> are invariant type. List<B>List<A>invariant类型。 What you need is covariant type.你需要的是covariant类型。 In this case, it is List<? extends A>在这种情况下,它是List<? extends A> List<? extends A> . List<? extends A>

Because generics are strict type safe .因为 generics 是严格类型安全的。

You can have你可以有

List<? extends A> aList = bList;

It says aList can hold list of any type which is an A它说aList可以保存任何类型的列表,它是A

Because List<B> does not extend List<A> .因为List<B>不扩展List<A> For example, Integer extends Number and so does Long .例如, Integer扩展NumberLong也是如此。 So List<Number> can contain both Integer and Long .所以List<Number>可以同时包含IntegerLong So if you assign List<Integer> to List<Number> you will be able to add Long to your list of integers.因此,如果您将List<Integer>分配给List<Number> ,您将能够将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.这将允许将包含 B 及其超类的任何列表分配给 superB。 But it's not the same as in your case aList=bList .但这与您的情况不同aList=bList

or或者

List<? extends A> extendsA;

Examples例子

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

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

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 ,但somethingA ,而A不是B

And that's why generics should be (and are) strict type safe.这就是为什么 generics 应该(并且是)严格类型安全的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM