我可以在java中反射性地实例化泛型类型吗?

2022-09-03 14:23:06

是否可以在 Java 中以反射方式实例化泛型类型?使用此处描述的技术,我收到一个错误,因为类令牌不能是泛型的。以下面的例子为例。我想实例化一些实现 Creator 的 Creator 子类。实际的类名作为命令行参数传入。这个想法是能够在运行时指定Creator的实现。有没有另一种方法可以完成我在这里想要做的事情?

public interface Creator<T> {
    T create();
}
public class StringCreator implements Creator<String> {
    public String create() { return new String(); }
}
public class FancyStringCreator implements Creator<String> {
    public String create() { return new StringBuffer().toString(); }
}
public static void main(String[] args) throws Exception {
    Class<?> someClass = Class.forName(args[0]);
    /*ERROR*/Class<? extends Creator<String>> creatorClass = someClass.asSubclass(Creator.class);
    Constructor<? extends Creator<String>> creatorCtor = creatorClass.getConstructor((Class<?>[]) null);
    Creator<String> creator = creatorCtor.newInstance((Object[]) null);
}

编辑:我喜欢Marcus的方法,因为它是最简单和务实的,同时又没有规避整个泛型的东西。我可以在我的情况下使用它,因为我可以指定传递的类必须是StringCreator的子类。但正如 Ericson 所指出的,泛型信息仍然存在于类型级别,而不是运行时级别,因此仍然可以反思性地检查给定类是否实现了正确的泛型类型。


答案 1

泛型信息在运行时丢失。没有与 Creator<String>.class 等效的运行时。您可以在 Creator 和 StringCreator 之间创建一个类型来修复泛型类型:

public interface Creator<T> {
        T create();
}
public interface StringCreator extends Creator<String> { }
public class StringCreatorImpl implements StringCreator  {
        public String create() { return new String(); }
}
public class FancyStringCreator implements StringCreator  {
        public String create() { return new StringBuffer().toString(); }
}
public static void main(String[] args) throws Exception {
        Class<?> someClass = Class.forName(args[0]);
        Class<? extends StringCreator> creatorClass = someClass.asSubclass(StringCreator.class);
        Constructor<? extends StringCreator> creatorCtor = creatorClass.getConstructor((Class<?>[]) null);
        Creator<String> creator = creatorCtor.newInstance((Object[]) null);
}

但是,当然,您失去了一些灵活性,因为您不能使用以下创建者类:

public class AnotherCreator implements Creator<String> {
    public String create() { return ""; }
}

答案 2

这将执行您在提供类型安全性时尝试执行的操作。无法避免未经检查的警告,但此处执行的类型检查证明了其抑制的合理性。

  public static void main(String[] args)
    throws Exception
  {
    Class<? extends Creator<String>> clz = load(argv[0], String.class);
    Constructor<? extends Creator<String>> ctor = clz.getConstructor();
    Creator<String> creator = ctor.newInstance();
    System.out.println(creator.create());
  }

  public static <T> Class<? extends Creator<T>> load(String fqcn, Class<T> type)
    throws ClassNotFoundException
  {
    Class<?> any = Class.forName(fqcn);
    for (Class<?> clz = any; clz != null; clz = clz.getSuperclass()) {
      for (Object ifc : clz.getGenericInterfaces()) {
        if (ifc instanceof ParameterizedType) {
          ParameterizedType pType = (ParameterizedType) ifc;
          if (Creator.class.equals(pType.getRawType())) {
            if (!pType.getActualTypeArguments()[0].equals(type))
              throw new ClassCastException("Class implements " + pType);
            /* We've done the necessary checks to show that this is safe. */
            @SuppressWarnings("unchecked")
            Class<? extends Creator<T>> creator = (Class<? extends Creator<T>>) any;
            return creator;
          }
        }
      }
    }
    throw new ClassCastException(fqcn + " does not implement Creator<String>");
  }

您必须遵守的主要限制是层次结构中的类必须指定 type 参数。例如。不能将其与 一起使用。class MyCreator implements Creator<String>class GenericCreator<T> implements Creator<T>

它目前不处理您创建新接口的有效情况,并有一个类实现它。这样做可以得到加强,但我会把它留给那些有倾向的人。interface StringCreatorIfc extends Creator<String>