问题
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.
回答1:
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.
回答2:
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.
回答3:
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);
}
}
回答4:
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();
回答5:
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.
来源:https://stackoverflow.com/questions/10803005/how-do-i-cast-a-list-from-a-subclass-generic-to-a-parent-class-generic