Is it possible to reflectively instantiate a generic type in Java? Using the technique described here I get an error because class tokens cannot be generic. Take the example below. I want to instantiate some subclass of Creator that implements Creator. The actual class name is passed in as a command line argument. The idea is to be able to specify an implementation of Creator at runtime. Is there another way to accomplish what I'm trying to do here?
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);
}
Edit: I like Marcus' approach as being the most simple and pragmatic without circumventing the whole generics thing. I can use it in my situation because I can specify that the class passed must be a subclass of StringCreator. But as Ericson pointed out the generic information is still there at the type level, just not at the runtime level so it is still possible to reflectively examine whether a given class implements the correct generic type.
“Java Generics are a language feature that allows for definition and use of generic types and methods.” Generic types are instantiated to form parameterized types by providing actual type arguments that replace the formal type parameters. A class like LinkedList<E> is a generic type, that has a type parameter E .
To use Java generics effectively, you must consider the following restrictions: Cannot Instantiate Generic Types with Primitive Types. Cannot Create Instances of Type Parameters.
You can create an instance of a generic class without specifying the actual type argument. An object created in this manner is said to be of a raw type. The Object type is used for unspecified types in raw types.
Java provides the new keyword to instantiate a class. We can also instantiate the above class as follows if we defining a reference variable. We observe that when we use the new keyword followed by the class name, it creates an instance or object of that class.
The generic information is lost in runtime. There is no runtime equivalent of a Creator<String>.class. You could create a type between Creator and 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 of course you lose a bit of flexibility, because you cannot use the following creator class:
public class AnotherCreator implements Creator<String> {
public String create() { return ""; }
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With