views:

1135

answers:

6

Suppose class B extends class A. I have a List<A> that I happen to know only contains instances of B. Is there a way I can cast the List<A> to a List<B>?

It seems my only option is to iterate over the collection, casting one element at time, creating a new collection. This seems like an utter waste of resources given type erasure makes this completely unnecessary at run-time.

A: 

No - you cannot cast directly from List<A> to List<B> since both are different types - your only option is to iterate through List<A> and cast every object of type A into a object of type B and add it to List<B>

Gambrinus
That's simply wrong.
jarnbjo
A: 

Unfortunately, there's no magic way. Type erasure is sometimes a pity :(

Sinuhe
Eh? If Java didn't have type erasure you wouldn't be able to do it. With erasure you can (but it is morally wrong).
Tom Hawtin - tackline
That's true! My mistake.
Sinuhe
A: 

Sadly, no. Even though B is an A, List<B> is not a List<A>.

So your iteration is the answer.

CPerkins
A: 

List<A> is not a subtype of List<B>!

The JLS even mentions that explicitly:

Subtyping does not extend through generic types: T <: U does not imply that C<T> <: C<U>.

Joachim Sauer
+8  A: 

You can cast through the untyped List interface:

List<A> a = new ArrayList<A>();
List<B> b = (List)a;
jarnbjo
And loose all type safety in the process! If `A` is a base class of `B`, then the list can contain `A`, while the code that handles `b` expects it to return only `B` objects. That's the very reason why that case is not allowed in the first place.
Joachim Sauer
@Joachim, I think that is the point of the original question. The only disadvantage of this approach over the traditional cast is that if you are wrong, the bug won't appear until much later and be harder to find, whereas an iteration would reveal your mistake.
Yishai
@Joachim - you **are** losing type-safety; the compiler cannot guarantee that the List<A> really is a List<B> which is why it won't let you do the cast in the first place. If you assert it yourself, that's fine, but this is *not* statically type-safe.
Andrzej Doyle
"I happen to know only contains instances of B". So long as he is only using the resulting list to retrieve elements and not to insert them (which could trigger a runtime check for a `checkedList`, for example), he should be fine.
Pavel Minaev
Pavel has it. The conditions of the question was that he was already convinced it only had instances of B. Without that condition, the question doesn't even make sense.
M1EK
A: 

You can try this :

List<A> a = new ArrayList<A>();
List<B> b = (List<B>) (List<?>) a;

It is based on the answer of jarnbjo, but on don't use raw lists.

Romain