是否可以创建一个List <class>,其中类在运行时反映出来?

时间:2015-10-02 18:36:58

标签: java generics reflection

因此,假设我使用反射来查找类的子类型(我正在使用Google Reflections库)。

Next i

现在我想通过遍历集合的成员为每个子类型创建一个列表,所以我想要这样的东西:

Set<Class<? extends Parent>> subTypes = reflections.getSubTypesOf(Parent.class);

但是,这不起作用,并且编译器在列表定义中抱怨“x是未知类”。

有没有办法根据反映的类型定义列表?

3 个答案:

答案 0 :(得分:1)

无法在Java中将反射类型用作类型参数。这也没用,因为Java泛型只在编译时才有用;一旦编译器完成,由于类型擦除,不同类型参数上的泛型类实例变得相同。

这意味着使用反射类型作为泛型参数的代码不会比具有替代父接口的泛型参数的代码(例如,在您的情况下为List<Parent>)或{{1}更有用。当没有公共基类/接口时。

答案 1 :(得分:1)

您可以定义

<T> static List<T> listForType(Class<T> elementType) {
  return new ArrayList<T>();
}

然后你可以试试

Class<X> xClass = cType;
List<X> listOfX = listForType(xClass);

但该语言无法以类型安全的方式从变体类型参数X生成不变类型参数? extends Parent

如果你的其他地方确实有一个不变的类型,只要子类型本身不是参数化类型,你就可以通过将未经检查的代码限制在一个小的地方来获得类型安全的代码。

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;
  } 
}

答案 2 :(得分:0)

如果您已经使用此部件:

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对象表示的类的新实例。   该类被实例化,就像一个带有空的新表达式一样   参数列表。如果尚未进行,则初始化该类   初始化。请注意,此方法会传播由此引发的任何异常   nullary构造函数,包括一个已检查的异常。使用此   方法有效地绕过了编译时异常检查   否则将由编译器执行。该   Constructor.newInstance方法通过包装任何方法来避免此问题   构造函数抛出的异常(已选中)   的InvocationTargetException。