How to define a generic type class?

I am creating a generic class and in one of the methods I need to know the class of the type of the generic type currently being used. The reason is because one of the methods that I call expects as an argument.

Example:

public class MyGenericClass<T> { public void doSomething() { // Snip... // Call to a 3rd party lib T bean = (T)someObject.create(T.class); // Snip... } } 

Obviously, the above example does not work and leads to the following error: Invalid class literal for a parameter of type T.

My question is: does anyone know a good alternative or workaround for this?

+55
java generics
Oct 08 '08 at 13:07
source share
6 answers

All the same problems: general information is deleted at runtime, it cannot be restored. The workaround is passing class T to the parameter of the static method:

 public class MyGenericClass<T> { private final Class<T> clazz; public static <U> MyGenericClass<U> createMyGeneric(Class<U> clazz) { return new MyGenericClass<U>(clazz); } protected MyGenericClass(Class<T> clazz) { this.clazz = clazz; } public void doSomething() { T instance = clazz.newInstance(); } } 

It is ugly, but it works.

+45
Oct 08 '08 at 13:12
source share

I just pointed out this solution:

 import java.lang.reflect.ParameterizedType; public abstract class A<B> { public Class<B> g() throws Exception { ParameterizedType superclass = (ParameterizedType) getClass().getGenericSuperclass(); return (Class<B>) superclass.getActualTypeArguments()[0]; } } 

This works if A specified by a particular subclass type:

 new A<String>() {}.g() // this will work class B extends A<String> {} new B().g() // this will work class C<T> extends A<T> {} new C<String>().g() // this will NOT work 
+21
Jan 15 '11 at 10:35
source share

Unfortunately, Christoph’s decision, as written, only works in very limited circumstances. [EDIT: as stated below, I no longer remember my reasoning for this sentence, and this is most likely incorrect: "Note that this will only work in abstract classes, first of all."] The next difficulty is that g() only works with DIRECT subclasses of A We can fix this, though:

 private Class<?> extractClassFromType(Type t) throws ClassCastException { if (t instanceof Class<?>) { return (Class<?>)t; } return (Class<?>)((ParameterizedType)t).getRawType(); } public Class<B> g() throws ClassCastException { Class<?> superClass = getClass(); // initial value Type superType; do { superType = superClass.getGenericSuperclass(); superClass = extractClassFromType(superType); } while (! (superClass.equals(A.class))); Type actualArg = ((ParameterizedType)superType).getActualTypeArguments()[0]; return (Class<B>)extractClassFromType(actualArg); } 

This will work in many situations in practice, but not ALL. Consider:

 public class Foo<U,T extends Collection<?>> extends A<T> {} (new Foo<String,List<Object>>() {}).g(); 

This will ClassCastException because the type argument here is not at all Class or ParameterizedType ; this is TypeVariable T So now you are stuck trying to figure out what type of T was supposed to stand, and so on down the rabbit hole.

I think the only reasonable general answer is something similar to Nicholas's original answer - in general, if your class needs to create objects of some other class that is not known at compile time, users of your class need to pass this to the class (or maybe a Factory) into your class explicitly and not rely solely on generics.

+4
Feb 07 2018-11-11T00:
source share

I will find another way to get a shared object class

 public Class<?> getGenericClass(){ Class<?> result =null; Type type =this.getClass().getGenericSuperclass(); if(type instanceofParameterizedType){ ParameterizedType pt =(ParameterizedType) type; Type[] fieldArgTypes = pt.getActualTypeArguments(); result =(Class<?>) fieldArgTypes[0]; } return result; } 
+2
Nov 09 '11 at 7:23
source share

T can be easily solved with TypeTools :

 Class<T> t = (Class<T>) TypeResolver.resolveRawArguments( MyGenericClass.class, getClass()); 
0
Oct 21 '13 at 17:13
source share

I will talk about the decision of Christophe.

Here is the abstract ClassGetter class:

 private abstract class ClassGetter<T> { public final Class<T> get() { final ParameterizedType superclass = (ParameterizedType) getClass().getGenericSuperclass(); return (Class<T>)superclass.getActualTypeArguments()[0]; } } 

Here is a static method that uses the above class to search for the type of a generic class:

 public static <T> Class<T> getGenericClass() { return new ClassGetter<T>() {}.get(); } 

As an example of using this method, you can make this method:

 public static final <T> T instantiate() { final Class<T> clazz = getGenericClass(); try { return clazz.getConstructor((Class[])null).newInstance(null); } catch (Exception e) { return null; } } 

And then use it like this:

 T var = instantiate(); 
0
Aug 11 '14 at
source share



All Articles