简体   繁体   中英

How do I cast a List from a subclass generic to a parent class generic?

I'm modifying open JDK to add features and I've run into this twice with no good solution.

There's a class named JCStatement which extends JCTree .

Issue: I want to cast a List<JCStatement> into a List<JCTree> .

It's clear that a class can reference one of its extensions, but when I have it on a List, it just doesn't work.

I used: (List<JCTree>)((List<?>)params) to cast, which works, but doesn't build on ant. IDE gives me the following warning:

Type safety: Unchecked cast from List<capture#1-of ?> to List<JCTree>

So this must be worked around somehow.

I appreciate any help.

You cannot make this cast.

What happens if you cast a List<JCStatement> to a List<JCTree> and then you add a JCTree (non JCStatement) object to that list? It breaks the List<JCStatement> type safety.

If you know you won't add any elements to the list -- so it will be type-safe -- then Collections.unmodifiableList(List<? extends E>) will return a List<E> .

This is totally type-safe and legit, because it enforces the guarantee that you'll never add an illegal element to the list, and it's provided by the JDK.

Would something like this work for you?

import java.util.ArrayList;
import java.util.List;

class A {
}

class B extends A {
}

class C extends A {
}

public class Program {
    public static void foo(List<? extends A> list) {
    }

    public static void main(String[] args) {
        List<A> listA = new ArrayList<A>();
        List<B> listB = new ArrayList<B>();
        List<C> listC = new ArrayList<C>();
        List<? extends A> listX = (List<? extends A>) listB;
        List<? extends A> listY = (List<? extends A>) listC;

        foo(listA);
        foo(listB);
        foo(listC);
        foo(listX);
        foo(listY);
    }
}

This seems to be an issue with the List, or generic types collections as general.

Simplest solution ever:

ListBuffer<JCTree> ls = new ListBuffer<JCTree>();
for(JCVariableDecl v : params){ ls.append(v); }
return ls.toList();

You can do it if you're really really sure it's safe by casting through the Raw Type

List<Number> listA = new LinkedList<Number>();
List<Integer> listB = new LinkedList<Integer>();
listA = (List<Number>)(List) listB;

I cannot imagine myself ever thinking that's a good solution to a problem, but it will do what you want, and there are some irritating limitations to compile time generics :)

There will always be a warning for a Unsafe cast, because what you're doing is in fact unsafe. There is no way for the compiler to make it safe, you have to be sure of that yourself.

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