Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Most efficient way to cast List<SubClass> to List<BaseClass>

People also ask

How do you cast a super class to a subclass?

You can try to convert the super class variable to the sub class type by simply using the cast operator. But, first of all you need to create the super class reference using the sub class object and then, convert this (super) reference type to sub class type using the cast operator.

Can a superclass object be cast to subclass?

As it was said before, you can't cast from superclass to subclass unless your object was instantiated from the subclass in the first place.

How do you cast a List in Java?

Try the following: List<TestA> result = new List<TestA>(); List<TestB> data = new List<TestB>(); result. addAll(data);

How do I cast a List of objects?

you can always cast any object to any type by up-casting it to Object first. in your case: (List<Customer>)(Object)list; you must be sure that at runtime the list contains nothing but Customer objects.


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.


erickson already explained why you can't do this, but here some solutions:

If you only want to take elements out of your base list, in principle your receiving method should be declared as taking a List<? extends BaseClass>.

But if it isn't and you can't change it, you can wrap the list with Collections.unmodifiableList(...), which allows returning a List of a supertype of the argument's parameter. (It avoids the typesafety problem by throwing UnsupportedOperationException on insertion tries.)


As @erickson explained, if you really want a reference to the original list, make sure no code inserts anything to that list if you ever want to use it again under its original declaration. The simplest way to get it is to just cast it to a plain old ungeneric list:

List<BaseClass> baseList = (List)new ArrayList<SubClass>();

I would not recommend this if you don't know what happens to the List and would suggest you change whatever code needs the List to accept the List you have.


I missed the answer where you just cast the original list, using a double cast. So here it is for completeness:

List<BaseClass> baseList = (List<BaseClass>)(List<?>)subList;

Nothing is copied, and the operation is fast. However, you are tricking the compiler here so you must make absolutely sure to not modify the list in such a way that the subList starts containing items of a different sub type. When dealing with immutable lists this is usually not an issue.


Below is a useful snippet that works. It constructs a new array list but JVM object creation over head is in-significant.

I saw other answers are un-necessarily complicated.

List<BaseClass> baselist = new ArrayList<>(sublist);

List<BaseClass> convertedList = Collections.checkedList(listOfSubClass, BaseClass.class)


What you are trying to do is very useful and I find that I need to do it very often in code that I write. An example use case:

Say we have an interface Foo and we have a zorking package which has a ZorkingFooManager which creates and manages instances of package-private ZorkingFoo implements Foo. (A very common scenario.)

So, ZorkingFooManager needs to contain a private Collection<ZorkingFoo> zorkingFoos but it needs to expose a public Collection<Foo> getAllFoos().

Most java programmers would not think twice before implementing getAllFoos() as allocating a new ArrayList<Foo>, populating it with all the elements from zorkingFoos and returning it. I enjoy entertaining the thought that about 30% of all clock cycles consumed by java code running on millions of machines all over the planet is doing nothing but creating such useless copies of ArrayLists which are garbage-collected microseconds after their creation.

The solution to this problem is, of course, down-casting the collection. Here is the best way to do it:

static <T,U extends T> List<T> downCastList( List<U> list )
{
    return castList( list );
}

Which brings us to the castList() function:

static <T,E> List<T> castList( List<E> list )
{
    @SuppressWarnings( "unchecked" )
    List<T> result = (List<T>)list;
    return result;
}

The intermediate result variable is necessary due to a perversion of the java language:

  • return (List<T>)list; produces an "unchecked cast" exception; so far so good; but then:

  • @SuppressWarnings( "unchecked" ) return (List<T>)list; is an illegal use of the suppress-warnings annotation.

So, even though it is not kosher to use @SuppressWarnings on a return statement, it is apparently fine to use it on an assignment, so the extra "result" variable solves this problem. (It should be optimized away either by the compiler or by the JIT anyway.)