Assuming the below statements work :
Collection<SomeType> collection;
Collection<OtherType> otherCollection = (Collection<OtherType>) collection; //illegal
This would break the type safety generics were supposed to provide. Imagine you could assign a Collection<SomeType>
to a Collection<OtherType>
. Then the following code would allow you to put something that wasn't a SomeType
into a Collection<SomeType>
:
otherCollection.add(new OtherType());
Because otherCollection
is a Collection<OtherType>
, adding a new OtherType()
to it seems perfectly legal. But otherCollection
is actually referring to a collection of type SomeType
.
And this is allowed:
Collection<SomeType> collection;
Collection<OtherType> otherCollection = (Collection<OtherType>) (Collection<?>) collection;
This is an implication of type erasure
. As generics are implemented almost entirely in the Java compiler, and not in the runtime, nearly all type information about generic types has been erased
by the time the bytecode is generated. So at runtime, Collection<SomeType>
and Collection<OtherType>
are the same class and both of them are subtypes of Collection<?>
. With this conversion, the compiler will simply emit an unchecked warning, because it doesn't know if the cast is safe or not.
But a casting, like the one you have given in the second example, should be avoided to avoid ClassCastException
at runtime. Consider the below series of statements:
Collection<SomeType> collection;
Collection<OtherType> otherCollection = (Collection<OtherType>) (Collection<?>) collection;
collection.add(new SomeType());
otherCollection.add(new OtherType());
Now after the 4th statement, there is no way for the original collection to tell what specific type of objects it contains; which might lead to ClassCastException
at runtime while accessing elements from the collection.