是否可以创建一个 List<class>,其中 class 在运行时反映出来?
Is it possible to create a List<class> where class is reflected at runtime?
假设我使用反射来查找 class' 子类型(我正在使用 Google 反射库)。
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 is an unknown class'。
有没有办法根据反射类型定义列表?
在 Java 中无法使用反射类型作为类型参数。这也是没有用的,因为 Java 泛型只有在编译时才有用;编译器完成后,由于类型擦除,不同类型参数上的泛型 class 实例变得相同。
这意味着使用反射类型作为泛型参数的代码不会比用泛型参数代替父接口的代码更有用(即在您的情况下为 List<Parent>
)或 List<Object>
当没有公共基础时 class / interface.
你可以定义
<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;
}
}
如果您已经在使用这部分:
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 的截取:
Creates a new instance of the class represented by this Class object.
The class is instantiated as if by a new expression with an empty
argument list. The class is initialized if it has not already been
initialized. Note that this method propagates any exception thrown by
the nullary constructor, including a checked exception. Use of this
method effectively bypasses the compile-time exception checking that
would otherwise be performed by the compiler. The
Constructor.newInstance method avoids this problem by wrapping any
exception thrown by the constructor in a (checked)
InvocationTargetException.
假设我使用反射来查找 class' 子类型(我正在使用 Google 反射库)。
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 is an unknown class'。
有没有办法根据反射类型定义列表?
在 Java 中无法使用反射类型作为类型参数。这也是没有用的,因为 Java 泛型只有在编译时才有用;编译器完成后,由于类型擦除,不同类型参数上的泛型 class 实例变得相同。
这意味着使用反射类型作为泛型参数的代码不会比用泛型参数代替父接口的代码更有用(即在您的情况下为 List<Parent>
)或 List<Object>
当没有公共基础时 class / interface.
你可以定义
<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;
}
}
如果您已经在使用这部分:
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 的截取:
Creates a new instance of the class represented by this Class object. The class is instantiated as if by a new expression with an empty argument list. The class is initialized if it has not already been initialized. Note that this method propagates any exception thrown by the nullary constructor, including a checked exception. Use of this method effectively bypasses the compile-time exception checking that would otherwise be performed by the compiler. The Constructor.newInstance method avoids this problem by wrapping any exception thrown by the constructor in a (checked) InvocationTargetException.