Aman J
Aman J

Reputation: 452

Java Generics with class object as generic type

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

Answers (4)

Lii
Lii

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

newacct
newacct

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

NoDataFound
NoDataFound

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:

  1. Use an interface if you have a common ground for theses classes (like JDBC Driver).
  2. Cast the raw list into a known type, for example using Class::isAssignableFrom.

Upvotes: 0

Eugene
Eugene

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

Related Questions