Say I have a parent interface/class like so
interface Parent<T> {}
And a number of implementing interfaces that fix the generic type.
interface Child extends Parent<Type> {}
Can I use reflection to get the instance of Class
representing T
if I have the Class
object for Child
. Something like this:
<T, I extends Parent<T>> I create(Class<I> type) {
Class<T> tType = ...
...
}
Currently I'm having tType
be passed in as a parameter, but I'd like to simplify things if I can.
A generic type is declared by specifying a type parameter in an angle brackets after a type name, e.g. TypeName<T> where T is a type parameter.
In order to use a generic type we must provide one type argument per type parameter that was declared for the generic type. The type argument list is a comma separated list that is delimited by angle brackets and follows the type name. The result is a so-called parameterized type.
If we want the actual type of a generic parameter, we should inject it to the class in another way (e.g. constructor parameter, abstract function that returns the actual type, etc...).
Yes, despite what the others have said, this info is available if you have access to the subclass' Class
object. You need to use getGenericSuperclass
along with getActualTypeArguments
.
ParameterizedType superClass = (ParameterizedType)childClass.getGenericSuperclass();
System.out.println(superClass.getActualTypeArguments()[0]);
In your example, the "actual" type argument should return the Class
for Type
.
If you need to do anything non-trivial with generic types at runtime, consider Guava's TypeToken
. It can answer your question (and many more!) while addressing some of the nuanced concerns raised by commenters:
private interface Parent<T> {}
private interface Intermediate<U, V> extends Parent<V> {}
private interface Child<Z> extends Comparable<Double>, Intermediate<Z, Iterable<String>> {}
public void exploreGuavaTypeTokens() {
final TypeToken<? super Child> token = TypeToken.of(Child.class).getSupertype(Parent.class);
final TypeToken<?> resolved = token.resolveType(Parent.class.getTypeParameters()[0]);
System.out.println(resolved); // "java.lang.Iterable<java.lang.String>"
final Class<?> raw = resolved.getRawType();
System.out.println(raw); // "interface java.lang.Iterable"
}
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