I have a basic question regarding assignm开发者_如何学Goent 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
To explain this, let me substitute "B" with Integer and "A" with Number. 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. 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.
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:
List <? extends A> aList = bList;
List<B>
is not 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:
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.
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)
List<B>
and List<A>
are invariant
type. What you need is covariant
type. In this case, it is List<? extends A>
.
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
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.
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
.
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
bList.add( something ); // Here's the problem
bList.add()
takes a B
, but something
is an A
, and an A
is not a B
!
And that's why generics should be (and are) strict type safe.
精彩评论