使用默认方法从参数化接口中提取类

时间:2017-09-22 08:41:14

标签: java reflection types

如何在接口中使用Java 8默认方法来提取参数化类型的类而不是使用抽象类?

选项1(失败):

public interface EpicCoolInterface<T> {

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

选项2(失败):

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
}

第三次尝试(成功但没有界面):

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 个答案:

答案 0 :(得分:1)

实际上,您需要的是通用类型推断。

虽然您的第三次尝试有效,但它仅适用于指定情境(该类直接扩展抽象类)。

您可以使用我的实用工具类GenericUtil的方法

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

您可以在github上找到源代码和javadoc。

对于您的问题,您可以像这样定义您的界面:

  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];
    }
  }

让我们测试一下我们的代码:

  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());
  }

输出:

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<?>