[ACCEPTED]-can I reflectively instantiate a generic type in java?-reflection
The generic information is lost in runtime. There 5 is no runtime equivalent of a Creator<String>.class. You 4 could create a type between Creator and 3 StringCreator which fixes the generic type:
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);
}
But 2 of course you lose a bit of flexibility, because 1 you cannot use the following creator class:
public class AnotherCreator implements Creator<String> {
public String create() { return ""; }
}
This will do what you are trying to do while 11 providing type safety. There's no way to 10 avoid an unchecked warning, but the type 9 checking done here justifies its suppression.
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>");
}
The 8 main restriction you have to adhere to is 7 that a class in the hierarchy must specify 6 the type parameter. For example class MyCreator implements Creator<String>
. You can't 5 use it with class GenericCreator<T> implements Creator<T>
.
It doesn't currently handle 4 the valid case where you create a new interface 3 interface StringCreatorIfc extends Creator<String>
, and have a class implement that. It could 2 be enhanced to do that, but I'll leave that 1 as an exercise for those inclined.
You don't need that line. Nor do you need 4 the constructor as you're just using the 3 default one. Just instantiate the class 2 directly:
public static void main(String[] args) throws Exception {
Class<?> someClass = Class.forName(args[0]);
Creator<String> creator = (Creator<String>) someClass.newInstance();
}
If you insist, you'll only be able 1 to get halfway there:
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);
}
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.