简体   繁体   中英

How to consume a List<Sub> being returned as List<Super>

I have a method that returns List<Super> . say List<Super> myMethod();

When calling that method, I want to cast the returned list to List<Sub> , knowing that its runtime type will be a List of Sub .

I know that List<Sub> subs = (List<Sub>) myMethod() won't work because generics are invariant.

However, List<? super Sub> subs = myMethod() List<? super Sub> subs = myMethod() works, the compile time type becomes List<Object> , so subs.get(0).mySubMethod() won't work.

What I end up with is that I have to explicitly cast it as ((Sub) subs.get(0)).mySubMethod()

How do I do this correctly without explicit casting on each element?

The shortest version is:

List<Sub> subs = (List) myMethod();

List is a "raw type"; you can convert from List to any List<...> without a cast.

Note that this is circumventing the type system in a fundamentally incorrect way; the list was constructed as an ArrayList<Super> (or similar), so it's actually incorrect to trick the compiler into letting you refer to it with a reference of type List<Sub> , even if it so happens that all of the list elements are of type Sub . (The same is true of msandiford's longer version above; it may look more generics-friendly, but it's actually just another way of doing the same fundamentally incorrect thing.)

But, due to type erasure, you can generally get away with it.


One correct approach would be to make the method itself generic:

<T extends Super> List<T> myMethod(final Class<T> clazz) {
    final List<T> ret = Collections.checkedList(new ArrayList<T>(), clazz);
    // ... add elements to ret ...
    return ret;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM