How do you cast a List of supertypes to a List of subtypes?

前端 未结 17 1272
面向向阳花
面向向阳花 2020-11-22 08:43

For example, lets say you have two classes:

public class TestA {}
public class TestB extends TestA{}

I have a method that returns a L

相关标签:
17条回答
  • 2020-11-22 09:02

    This is possible due to type erasure. You will find that

    List<TestA> x = new ArrayList<TestA>();
    List<TestB> y = new ArrayList<TestB>();
    x.getClass().equals(y.getClass()); // true
    

    Internally both lists are of type List<Object>. For that reason you can't cast one to the other - there is nothing to cast.

    0 讨论(0)
  • 2020-11-22 09:03

    You can use the selectInstances method in Eclipse Collections. This will involved creating a new collection however so will not be as efficient as the accepted solution which uses casting.

    List<CharSequence> parent =
            Arrays.asList("1","2","3", new StringBuffer("4"));
    List<String> strings =
            Lists.adapt(parent).selectInstancesOf(String.class);
    Assert.assertEquals(Arrays.asList("1","2","3"), strings);
    

    I included StringBuffer in the example to show that selectInstances not only downcasts the type, but will also filter if the collection contains mixed types.

    Note: I am a committer for Eclipse Collections.

    0 讨论(0)
  • 2020-11-22 09:04

    You cannot cast List<TestB> to List<TestA> as Steve Kuo mentions BUT you can dump the contents of List<TestA> into List<TestB>. Try the following:

    List<TestA> result = new List<TestA>();
    List<TestB> data = new List<TestB>();
    result.addAll(data);
    

    I've not tried this code so there are probably mistakes but the idea is that it should iterate through the data object adding the elements (TestB objects) into the List. I hope that works for you.

    0 讨论(0)
  • 2020-11-22 09:04

    The problem is that your method does NOT return a list of TestA if it contains a TestB, so what if it was correctly typed? Then this cast:

    class TestA{};
    class TestB extends TestA{};
    List<? extends TestA> listA;
    List<TestB> listB = (List<TestB>) listA;
    

    works about as well as you could hope for (Eclipse warns you of an unchecked cast which is exactly what you are doing, so meh). So can you use this to solve your problem? Actually you can because of this:

    List<TestA> badlist = null; // Actually contains TestBs, as specified
    List<? extends TestA> talist = badlist;  // Umm, works
    List<TextB> tblist = (List<TestB>)talist; // TADA!
    

    Exactly what you asked for, right? or to be really exact:

    List<TestB> tblist = (List<TestB>)(List<? extends TestA>) badlist;
    

    seems to compile just fine for me.

    0 讨论(0)
  • 2020-11-22 09:07

    casting of generics is not possible, but if you define the list in another way it is possible to store TestB in it:

    List<? extends TestA> myList = new ArrayList<TestA>();
    

    You still have type checking to do when you are using the objects in the list.

    0 讨论(0)
  • 2020-11-22 09:08

    Quite strange that manually casting a list is still not provided by some tool box implementing something like:

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static <T extends E, E> List<T> cast(List<E> list) {
        return (List) list;
    }
    

    Of course, this won't check items one by one, but that is precisely what we want to avoid here, if we well know that our implementation only provides the sub-type.

    0 讨论(0)
提交回复
热议问题