This question already has an answer here:
Just come across with this problem:
List<DataNode> a1 = new ArrayList<DataNode>();
List<Tree> b1 = a1; // compile error: incompatible type
Where the type DataNode is a subtype of Tree.
public class DataNode implements Tree
To my surprise, this works for array:
DataNode[] a2 = new DataNode[0];
Tree[] b2 = a2; // this is okay
This likes a bit strange. Can anyone give an explanation on this?
DataNode might be a subtype of Tree, but List DataNode is not a subtype of List Tree.
https://docs.oracle.com/javase/tutorial/extra/generics/subtype.html
Well, I'll be honest here: lazy genericity implementation.
There's no semantic reason not to allow your first affectation.
Incidentally, though I adored templating in C++, generics, together with the kind of silly limitation we have here, are the main reason why I gave up on Java.
If you do have to cast from
List<DataNode>
toList<Tree>
, and you know it is safe to do so, then an ugly way to achieve this is to do a double-cast:List<DataNode> a1 = new ArrayList<DataNode>();
List<Tree> b1 = (List<Tree>) (List<? extends Tree>) a1;
It is the answer from C#, but I think it doesn't actually matter here, as the reason is the same.
"In particular, unlike array types, constructed reference types do not exhibit “covariant” conversions. This means that a type List<B> has no conversion (either implicit or explicit) to List<A> even if B is derived from A. Likewise, no conversion exists from List<B> to List<object>.
The rationale for this is simple: if a conversion to List<A> is permitted, then apparently one can store values of type A into the list. But this would break the invariant that every object in a list of type List<B> is always a value of type B, or else unexpected failures may occur when assigning into collection classes."
http://social.msdn.microsoft.com/forums/en-US/clr/thread/22e262ed-c3f8-40ed-baf3-2cbcc54a216e