2

How can I use a Java 8 default method in an interface to extract the Class of a Parameterized Type instead of using an abstract class?

Option 1 (Fails):

public interface EpicCoolInterface<T> {

 default Class<T> getParameterizedTypeClass() {
    return T.class; //doesn't work
}

Option 2 (Fails):

public interface EpicCoolInterface<T> {

 default Class<T> getParameterizedTypeClass() {
    return (Class<T>) ((ParameterizedType) getClass().getGenericInterfaces()[0])
    .getActualTypeArguments()[0];
    //java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
}

Third attempt (successful but no interface):

public abstract class CoolAbstractClass<T> {

  private Class<T> clazz;

  public CoolAbstractClass() {
    try {
      this.clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass())
          .getActualTypeArguments()[0];
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  public Class<T> getType() {
    return clazz;
  }
}

1 Answer 1

1

Actually, what you need is generic type inference.

Although your third attempt works, it only be applicable to specify situation(the class directly extends the abstract class).

You can use my utility class GenericUtil's method

Type[] getGenericTypes(Type sourceType, Class<?> targetClass)

You can find the source code and javadoc on github.

For your question, you can define your inteerface like this:

  public static interface EpicCoolInterface<T> {
    // Return Type rather than Class, because T not always be a class.
    // You can do type check and return Class<T> with force typecast.
    default Type getParameterizedTypeClass() {
      return GenericUtil.getGenericTypes(getClass(), EpicCoolInterface.class)[0];
    }
  }

And let's test our code:

  public static void main(String[] args) {
    EpicCoolInterface<Integer> a = new EpicCoolInterface<Integer>() {
    };
    System.out.println(a.getParameterizedTypeClass());
    EpicCoolInterface<EpicCoolInterface<Integer>> b = new EpicCoolInterface<EpicCoolInterface<Integer>>() {
    };
    System.out.println(b.getParameterizedTypeClass());
    EpicCoolInterface<EpicCoolInterface<?>> c = new EpicCoolInterface<EpicCoolInterface<?>>() {
    };
    System.out.println(c.getParameterizedTypeClass());
  }

it output:

class java.lang.Integer
xdean.stackoverflow.java.reflection.Q46360416.xdean.stackoverflow.java.reflection.Q46360416$EpicCoolInterface<java.lang.Integer>
xdean.stackoverflow.java.reflection.Q46360416.xdean.stackoverflow.java.reflection.Q46360416$EpicCoolInterface<?>
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.