如何在接口中获取泛型实例

时间:2018-06-23 19:27:13

标签: java generics

我有一个通用接口

public interface MessageCallback<T extends JsonModel> {
     void onMessage(T t);
}

我想获得T的实例。 我找到了可以使用反射的解决方案

public static <T> Class<T> getGenericClass(Class actualClass, int index) {
    ParameterizedType genericSuperclass = (ParameterizedType) actualClass.getGenericSuperclass();

    // Get generic class
    return (Class<T>) genericSuperclass.getActualTypeArguments()[index];
}

但是它引发异常。

java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType

我想知道有没有不使用反射的解决方案吗?

额外。我也找到了

class Foo<T> {
final Class<T> typeParameterClass;

public Foo(Class<T> typeParameterClass) {
    this.typeParameterClass = typeParameterClass;
}

public void bar() {
    // you can access the typeParameterClass here and do whatever you like
}
}

但仅适用于上课。我该如何解决我的问题?感谢您的回答。

如果您想知道它不是干净的Java。在Android中

2 个答案:

答案 0 :(得分:1)

关于您的第一个代码,Class.getGenericSuperclass()返回表示this类的直接超类的类型,在您的情况下为Object

Class.getGenericInterfaces()返回表示Type类直接实现的接口this,这是检索{{ 1}}界面。
但这可能对您没有帮助,因为泛型类型将是在MessageCallback接口:MessageCallback中静态声明的类型,而不是在扩展该接口的子类声明中定义的类型。

关于第二个代码,您不必担心捕获泛型的参数是JsonModel还是Class。 例如,在通用类(例如Type中声明的类型或在通用类(例如interface MessageCallback<T extends JsonModel>的子类中声明的类型)是必需的类,因为参数化类型只能是MessageCallbackImpl extends MessageCallback<MyJsonModel> es。因此,将通用类型的类型存储为Class是完全有效的。
Class类是Java中所有类型通用的超级接口类(原始类型,参数化类型,数组类型,类型变量和基本类型)

所以回到您的问题:您需要的是在运行时引用编译时定义的泛型类型的方法,而这种惯用语是实现此目的的经典方法:

Type

答案 1 :(得分:0)

您在正确的轨道上。 现在假设我们有一个通用接口,如您的示例所示:

public interface MessageCallback<T extends JsonModel> {
     void onMessage(T t);
}

及其具体实现:

class FooMessage {}

public class MyMessageCallback 
       implements MessageCallback<FooMessage extends JsonModel> {
    @Override
    public void onMessage(FooMessage t) {
        System.out.println("Received foo");
    }
}

您要查找传递到通用接口MessageCallback(在本例中为FooMessage)中的类型。

我们可以使用反射来查找MyMessageCallback实现的所有接口,并为每个接口检查它是否为通用接口,然后返回其所有类型参数。

public static <T> Class<?>[] getGenericInterfaceParameter(Class clazz, Class<T> interfaceType) {
    Class<?>[] result = new Class<?>[0];
    // make sure interfaceType is a generic interface.
    if(!interfaceType.isInterface() || interfaceType.getTypeParameters().length < 1) {
        return result;
    }
    // get all interfaces implemented by concrete class.
    Type[] interfaceTypes = clazz.getGenericInterfaces();

    // for each interface the concrete class implements
    // we check if that interface is actually equal to interfaceType
    // and is a parametrized type,
    // i.e has a type parameter.
    // Once a match is found, we return the type parameters.
    for(Type it : interfaceTypes) {
        if(it instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) it;
            if(!parameterizedType.getRawType().equals(interfaceType)) {
                continue;
            }
            Type[] typeParameters = parameterizedType.getActualTypeArguments();
            result = new Class[typeParameters.length];
            for(int j = 0; j < typeParameters.length; j++) {
                result[j] = (Class) typeParameters[j];
            }
        }
    }

    return result;
}

使用该方法查找MyMessageCallback的类型参数:

Class<?>[] params = getGenericInterfaceParameter(
                       MyCallback.class,
                       MessageCallback.class
                    );
System.out.println(params[0].getTypeName()); // MyMessageCallback