假设我使用反射来查找类的子类型(我使用谷歌反射库)。
Set<Class<? extends Parent>> subTypes = reflections.getSubTypesOf(Parent.class);
现在我想通过遍历集合的成员为每个子类型创建一个列表,所以我想要这样做:
try {
for (Class<? extends Parent> cType : subTypes.iterator()) {
Class x = Class.forName(cType.getName());
List<x> list = new ArrayList<x>();
}
} catch(ClassNotFoundException ex){
...
}
然而,这不起作用,编译器报错"x是列表定义中的未知类"。
是否有一种方法来定义基于反射类型的列表?
你可以定义
<T> static List<T> listForType(Class<T> elementType) {
return new ArrayList<T>();
}
然后你可以试试
Class<X> xClass = cType;
List<X> listOfX = listForType(xClass);
但是语言无法以类型安全的方式从可变类型参数? extends Parent
生成不变类型参数X
如果在其他地方有一个不变类型,只要子类型本身不是参数化类型,就可以通过将未检查的代码限制在较小的位置来获得类型安全的代码。
final class ListPerSubType {
private final Map<Class<? extends Parent>, List> listPerSubType = new LinkedHashMap<>();
public <T extends Parent> List<T> get(Class<T> cl) {
// TODO: throw IllegalArgument if cl is parameterized.
if (!listPerSubType.containsKey(cl)) {
listPerSubType.put(cl, new ArrayList<T>());
}
List list = listPerSubType.get(cl);
// This is type-safe since no other code exposes the
// lists via type not gained from a type token.
@SuppressWarnings("unchecked")
List<T> typedList = list;
return list;
}
}
在Java中不可能使用反射类型作为类型参数。这也是没有用的,因为Java泛型只在编译时有用;一旦编译器完成,由于类型擦除,不同类型参数上的泛型类实例变得相同。
这意味着当没有公共基类/接口时,使用反射类型作为泛型参数的代码不会比用泛型参数代替父接口(即您的情况下的List<Parent>
)或List<Object>
的代码更有用。
如果您已经让这部分工作:
Set<Class<? extends Parent>> subTypes =
reflections.getSubTypesOf(Parent.class);
我想如果你做下面所示的更改,你就会解决你的问题。
public <P extends Parent> void handleSubTypes(Set<Class<P>> subTypes) {
try {
for (Class<P> sType : subTypes) {
P instance = sType.newInstance();
List<P> list = new ArrayList<P>();
}
} catch (InstantiationException e) {
// ...
} catch (IllegalAccessException e) {
// ...
}
}
下面是Class.newInstance()
JavaDoc的剪辑:
创建由class对象表示的类的新实例。类被实例化,就像用一个空的new表达式一样参数列表。如果类还没有初始化,则对其进行初始化初始化。请注意,此方法传播由。抛出的任何异常虚参构造函数,包括已检查的异常。这个的用法方法有效地绕过编译时异常检查否则将由编译器执行。的构造函数。newInstance方法通过包装任何构造函数在(checked)中抛出的异常InvocationTargetException .