Reputation: 284
Imagine I have an abstract class defining a Generic Type
. All subclasses will implement this Generic Type.
I can achive so by declaring a abstract method that forces the subclass to return that type. But is there a more elegant way to achieve this directly from the 'Class' object definition of the subclass?
public class GenericTest {
public static void main(String[]args) throws Exception{
Class strClass = ClazzImplString.class;
Class intClass = ClazzImplInteger.class;
Class implTypeStr = ((AbsClazz)strClass.getConstructor().newInstance()).getGenericType();
Class implTypeInt = ((AbsClazz)intClass.getConstructor().newInstance()).getGenericType();
System.out.println("implTypeStr: " + implTypeStr);
System.out.println("implTypeInt: " + implTypeInt);
}
}
abstract class AbsClazz<GenericType> {
abstract Class getGenericType();
}
class ClazzImplString extends AbsClazz<String> {
public ClazzImplString() {}
@Override Class getGenericType() {return String.class;}
}
class ClazzImplInteger extends AbsClazz<Integer> {
public ClazzImplInteger() {}
@Override Class getGenericType() {return Integer.class;}
}
Thank you in advance
Upvotes: 4
Views: 241
Reputation: 62864
You can set the return type for your abstract method to be the Class
, parametrized with the generic type:
abstract class AbsClazz<T> {
abstract Class<T> getGenericType();
}
Then, in your subclasses, you will be forced to implement a method, that returns the type provided in the class definition. For example:
class ClazzImplString extends AbsClazz<String> {
public ClazzImplString() {}
@Override Class<String> getGenericType() {return String.class;}
}
Upvotes: 5
Reputation: 6197
You can avoid the getGenericType
on each subtype getting ParameterizedType
from subtypes.
An example look like this:
public abstract class AbsClazz<E extends Serializable> { }
public class ClazzImplInteger extends AbsClazz<Integer> { }
public class ClazzImplString extends AbsClazz<String> { }
public class GenericTest {
public static void main(String[] args) {
System.out.println("implTypeStr: " + getTypeFromGenericClass(ClazzImplString.class, 0));
System.out.println("implTypeInt: " + getTypeFromGenericClass(ClazzImplInteger.class, 0));
}
public static Class<?> getTypeFromGenericClass(final Class<?> genericType, final Integer index) {
final ParameterizedType type = (ParameterizedType) genericType.getGenericSuperclass();
return (Class<?>) type.getActualTypeArguments()[index];
}
}
This example will print:
implTypeStr: class java.lang.String
implTypeInt: class java.lang.Integer
Upvotes: 1
Reputation: 18861
Here is one crazy hack with reflection:
import java.lang.reflect.ParameterizedType;
class GenericClazz<T> {
public Class<T> getType() {
return (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
}
(source - one of my old projects: link)
Upvotes: 2
Reputation: 279930
Yes, you can use reflection.
ParameterizedType genericSuperclass = (ParameterizedType) ClazzImplString.class.getGenericSuperclass();
Class<?> clazz = (Class<?>) genericSuperclass.getActualTypeArguments()[0];
System.out.println(clazz); // prints class java.lang.String
Upvotes: 5