I have a List<SubClass>
that I want to treat as a List<BaseClass>
. It seems like it shouldn’t be a problem since casting a SubClass
to a BaseClass
is a snap, but my compiler complains that the cast is impossible.
So, what’s the best way to get a reference to the same objects as a List<BaseClass>
?
Right now I’m just making a new list and copying the old list:
List<BaseClass> convertedList = new ArrayList<BaseClass>(listOfSubClass)
But as I understand it that has to create an entirely new list. I’d like a reference to the original list, if possible!
Advertisement
Answer
The syntax for this sort of assignment uses a wildcard:
List<SubClass> subs = ...; List<? extends BaseClass> bases = subs;
It’s important to realize that a List<SubClass>
is not interchangeable with a List<BaseClass>
. Code that retains a reference to the List<SubClass>
will expect every item in the list to be a SubClass
. If another part of code referred to the list as a List<BaseClass>
, the compiler will not complain when a BaseClass
or AnotherSubClass
is inserted. But this will cause a ClassCastException
for the first piece of code, which assumes that everything in the list is a SubClass
.
Generic collections do not behave the same as arrays in Java. Arrays are covariant; that is, it is allowed to do this:
SubClass[] subs = ...; BaseClass[] bases = subs;
This is allowed, because the array “knows” the type of its elements. If someone attempts to store something that isn’t an instance of SubClass
in the array (via the bases
reference), a runtime exception will be thrown.
Generic collections do not “know” their component type; this information is “erased” at compile time. Therefore, they can’t raise a runtime exception when an invalid store occurs. Instead, a ClassCastException
will be raised at some far distant, hard-to-associate point in code when a value is read from the collection. If you heed compiler warnings about type safety, you will avoid these type errors at runtime.