Reputation: 452
I want to create a Java Object for a class that is defined using generics. Specifically, i want to create a List of Objects of class that is determined at runtime.
I would want something like
Class clazz = Class.forName("MyClass");
List<clazz> myList = new ArrayList<>(); // This isn't allowed
Defining an array of object would allow me to store a list of MyClass type objects, but that would lead to casting the objects every-time the object is fetched from the list, i would like to avoid such a scenario.
Is there a way to achieve something like the above code using java.
Upvotes: 1
Views: 3462
Reputation: 12112
There is a little trick that can be used to work with a specific unknown type: Declare a type parameter that is only used for the unknown type:
public <T> void worksWithSomeUnknownClass() throws ReflectiveOperationException {
@SuppressWarnings("unchecked")
Class<T> clazz = (Class<T>) Class.forName("MyClass");
T obj = clazz.getConstructor().newInstance();
List<T> myList = new ArrayList<>();
myList.add(obj);
}
This solution is very limited though. It makes sure that you don't mix it up with other unknown types or Object
, but you can not really do anything with T
. And you have to declare a type parameter on every method that uses it.
Upvotes: 0
Reputation: 122429
No, you can't. Generics in Java is just a compile-time type checking mechanism. If you don't know the type until runtime, then, obviously, it cannot be used for compile-time type checking. The compiler can't determine at compile time what types to allow you to put into or get out of a List<clazz>
, so it's no more meaningful than just a raw type List
.
Upvotes: 0
Reputation: 11949
As I understand your question, you want to know if is possible for the compiler to know the runtime type while it is limited to the compile type.
You can't. And your hypothesis is also wrong:
Defining an array of object would allow me to store a list of MyClass type objects, but that would lead to casting the objects every-time the object is fetched from the list, i would like to avoid such a scenario.
In Java, generics does not remove the cast: it is still there in the form of type erasure and (hidden) cast. When you do List<String>
, you merely ask the compiler to hide the cast in operation such as T get(int)
: there will be a cast to String
.
If you want to use the compile time information, than that would mean you already have/know the type MyClass
available at compile time and you would not use Class::forName
but MyClass.class
which would return a Class<MyClass>
.
What you can do is either:
Driver
).Class::isAssignableFrom
.Upvotes: 0
Reputation: 120848
Well, since you know that class, you could (with a warning) cast the List
itself; but you would still need to know the class name and some checks for that, like for example:
if(clazz.getName().equals("java.lang.String")) {
// warning here
yourList = (List<String>) yourList;
}
Upvotes: 1