Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting generic parameter from supertype class

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.

like image 631
sblundy Avatar asked Mar 29 '12 22:03

sblundy


People also ask

How do you indicate that a class has a generic type parameter?

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.

How do you provide a generic parameterized type?

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.

How do you find the type of generic class?

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...).


2 Answers

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.

like image 189
Kirk Woll Avatar answered Sep 26 '22 22:09

Kirk Woll


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"
}
like image 34
Woody Zenfell III Avatar answered Sep 24 '22 22:09

Woody Zenfell III