是否有可能在Java中反射性地实例化泛型类型?使用描述的here技术,我得到一个错误,因为类标记不能是通用的。以下面的例子为例。我想实例化一些实现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);
}
编辑:我喜欢马库斯的方法是最简单务实的,不会绕过整个仿制品。我可以在我的情况下使用它,因为我可以指定传递的类必须是StringCreator的子类。但正如Ericson所指出的那样,通用信息仍然存在于类型级别,而不是在运行时级别,因此仍然可以反思地检查给定的类是否实现了正确的泛型类型。
答案 0 :(得分:9)
通用信息在运行时丢失。没有运行时等效的Creator&lt; String&gt; .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 ""; }
}
答案 1 :(得分:5)
这将在提供类型安全性的同时完成您要做的事情。没有办法避免未经检查的警告,但这里完成的类型检查证明了它的抑制。
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>
的有效情况,并且具有类实现。可以通过增强来做到这一点,但我会把它留给那些倾向的人。
答案 2 :(得分:3)
你不需要那条线。您也不需要构造函数,因为您只使用默认构造函数。直接实例化该类:
public static void main(String[] args) throws Exception {
Class<?> someClass = Class.forName(args[0]);
Creator<String> creator = (Creator<String>) someClass.newInstance();
}
如果你坚持,你只能到达那里:
public static void main(String[] args) throws Exception {
Class<?> someClass = Class.forName(args[0]);
Class<? extends Creator> creatorClass = someClass.asSubclass(Creator.class);
Constructor<? extends Creator> creatorCtor = creatorClass.getConstructor((Class<?>[]) null);
Creator<String> creator = (Creator<String>) creatorCtor.newInstance((Object[]) null);
}
答案 3 :(得分:-1)
不太清楚为什么你在这里使用泛型。
使用反射对象的实例化会建议一般使用,但可能你会在某个时刻调用create
并将结果分配给String
,否则为什么要使用泛型来控制返回类型。
但是如果您编写了以下Creator实现:
public class IntegerCreator implements Creator<Integer>
{
public Integer create()
{
...
}
}
作为参数传递它,在调用create
并分配结果时会得到ClassCastException。