Java 从泛型基接口的实例检索类型参数

Java 从泛型基接口的实例检索类型参数,java,generics,reflection,Java,Generics,Reflection,给定2个接口: public interface BaseInterface<T> { } public interface ExtendedInterface<T0, T1> extends BaseInterface<T0> {} 但是我找不到一种简单的方法可以递归到任何基本泛型接口中,并从中获取任何有意义的内容。我不认为您可以,因为这些接口实际上是特定于实例的,而不是特定于类的。考虑以下事项: List<String> a = new A

给定2个接口:

public interface BaseInterface<T> { }
public interface ExtendedInterface<T0, T1> extends BaseInterface<T0> {}

但是我找不到一种简单的方法可以递归到任何基本泛型接口中,并从中获取任何有意义的内容。

我不认为您可以,因为这些接口实际上是特定于实例的,而不是特定于类的。考虑以下事项:

List<String>  a = new ArrayList<String>();
List a=new ArrayList();

字符串列表是通用的,这一事实特定于实例a,而不是类列表。因此,List.class对象的任何方法都不能告诉您泛化类型将是a的String类型。虽然在您的示例中MyClass碰巧为接口的genericized类型设置了值,但我认为这在接口类对象实例中不可用。

我认为我能想到的唯一选项是检查由
BaseInterface
声明的通用方法,不被覆盖。

我不知道你到底想实现什么,知道什么和不知道什么,但你可以像这样递归到超级界面:

Type[] interfaces = MyClass.class.getGenericInterfaces();

ParameterizedType extInterfaceType = (ParameterizedType)interfaces[0];
Class<?> extInterfaceClass = (Class<?>)extInterfaceType.getRawType();

Type[] baseInterfaces = extInterfaceClass.getGenericInterfaces();
ParameterizedType baseInterfaceType = (ParameterizedType)baseInterfaces[0];
Class<?> baseInterfaceClass = (Class<?>)baseInterfaceType.getRawType();
public interface BaseInterface<T> {
    Class<T> getGenericClass();
}
我认为没有一种直接的方法可以获得基本接口的泛型类型

一种方法是在接口中声明如下方法:

Type[] interfaces = MyClass.class.getGenericInterfaces();

ParameterizedType extInterfaceType = (ParameterizedType)interfaces[0];
Class<?> extInterfaceClass = (Class<?>)extInterfaceType.getRawType();

Type[] baseInterfaces = extInterfaceClass.getGenericInterfaces();
ParameterizedType baseInterfaceType = (ParameterizedType)baseInterfaces[0];
Class<?> baseInterfaceClass = (Class<?>)baseInterfaceType.getRawType();
public interface BaseInterface<T> {
    Class<T> getGenericClass();
}

我回答我自己的问题时又犯了一次不礼貌的错误

正如gix所指出的,当您开始沿着泛型类型的层次结构前进时,除了第一个层次结构之外,您将丢失有关类型参数的信息

但重要的是:您可以获得要实例化的第一个泛型接口(在我的示例中为ExtendedInterface)的类型参数,还可以获得用于创建子接口的类型参数的名称

因此,通过保持TypeVariable名称到实际类型参数的映射,可以确定基本接口的类型参数

稍后我将使用一些代码进行更新,但它确实有效(您可以从MyClass.class确定用于实例BaseInterface的类型参数)

更新 这是第一次通过一些简单的单元测试。它需要工作。。。真正的问题是,这个问题值得如此可笑的解决方案吗

public class GenericReflectionUtils
{
@SuppressWarnings("unchecked")
public static List<Class> getGenericInterfaceTypeArguments(Class baseInterface, Class concreteClass)
{
    if (!baseInterface.isAssignableFrom(concreteClass))
    {
        throw new IllegalArgumentException("Illegal base interface argument");
    }
    if (concreteClass.getTypeParameters().length > 0)
    {
        throw new IllegalArgumentException("Can't determine the type arguments of a generic interface of a generic class");
    }
    for (Type genericInterface : concreteClass.getGenericInterfaces())
    {
        List<Class> result = null;
        if (genericInterface instanceof Class)
        {
            result = getGenericInterfaceTypeArguments(baseInterface,(Class)genericInterface);
        }
        else
        {
            result = getGenericInterfaceTypeArguments(baseInterface, (ParameterizedType)genericInterface);
        }
        if (result != null)
        {
            return result;
        }
    }
    return null;
}


public static Class getClass(Type type)
{
    if (type instanceof Class)
    {
        return (Class) type;
    }
    if (type instanceof ParameterizedType)
    {
        return getClass(((ParameterizedType) type).getRawType());
    }
    if (type instanceof GenericArrayType)
    {
        Type componentType = ((GenericArrayType) type).getGenericComponentType();
        Class<?> componentClass = getClass(componentType);
        if (componentClass != null)
        {
            return Array.newInstance(componentClass, 0).getClass();
        }
        return null;
    }
    return null;
}

@SuppressWarnings("unchecked")
private static List<Class> getGenericInterfaceTypeArguments(Class baseInterface, ParameterizedType currentType)
{
    Class currentClass = getClass(currentType);
    if (!baseInterface.isAssignableFrom(currentClass))
    {
        //  Early out - current type is not an interface that extends baseInterface
        return null;
    }

    Type[] actualTypeArguments = currentType.getActualTypeArguments();

    if (currentClass == baseInterface)
    {
        //  currentType is a type instance of the base generic interface. Read out the type arguments and return 
        ArrayList<Class> typeArgs = new ArrayList<Class>(actualTypeArguments.length);
        for (Type typeArg : actualTypeArguments)
        {
            typeArgs.add(getClass(typeArg));
        }

        return typeArgs;
    }

    //  currentType is derived
    Map<String, Class> typeVarMap = createTypeParameterMap(currentType, null);

    for (Type genericInterfaceType : currentClass.getGenericInterfaces())
    {
        List<Class> result = getGenericInterfaceTypeArguments(baseInterface, (ParameterizedType)genericInterfaceType, typeVarMap);
        if (result != null)
        {
            return result;
        }
    }
    return null;
}

private static Map<String, Class> createTypeParameterMap(ParameterizedType type, Map<String, Class> extendedTypeMap)
{
    Map<String, Class> typeVarMap = new HashMap<String, Class>();
    Type[] typeArgs = type.getActualTypeArguments();
    TypeVariable[] typeVars = getClass(type).getTypeParameters();
    for (int typeArgIndex = 0; typeArgIndex < typeArgs.length; ++typeArgIndex)
    {
        //  Does not deal with nested generic arguments...
        Type typeArg = typeArgs[typeArgIndex];
        if (typeArg instanceof TypeVariable)
        {
            assert extendedTypeMap != null;
            TypeVariable typeVar = (TypeVariable)typeArg;
            typeVarMap.put(typeVars[typeArgIndex].getName(), extendedTypeMap.get(typeVar.getName()));
            continue;
        }
        typeVarMap.put(typeVars[typeArgIndex].getName(), getClass(typeArgs[typeArgIndex]));
    }

    return typeVarMap;
}

private static List<Class> createTypeParameterList(Map<String, Class> typeParameterMap, ParameterizedType type)
{
    ArrayList<Class> typeParameters = new ArrayList<Class>(typeParameterMap.size());
    for (Type actualType : type.getActualTypeArguments())
    {
        if (actualType instanceof TypeVariable)
        {
            //  Handles the case when an interface is created with a specific type, rather than a parameter
            typeParameters.add(typeParameterMap.get(((TypeVariable)actualType).getName()));
            continue;
        }
        typeParameters.add(getClass(actualType));
    }
    return typeParameters;
}

@SuppressWarnings("unchecked")
private static List<Class> getGenericInterfaceTypeArguments(Class baseInterface, ParameterizedType currentType, Map<String, Class> currentTypeParameters)
{
    Class currentClass = getClass(currentType);
    if (!baseInterface.isAssignableFrom(currentClass))
    {
        //  Early out - current type is not an interface that extends baseInterface
        return null;
    }

    if (currentClass == baseInterface)
    {
        return createTypeParameterList(currentTypeParameters, currentType);
    }

    currentTypeParameters = createTypeParameterMap(currentType, currentTypeParameters);
    for (Type genericInterface : currentClass.getGenericInterfaces())
    {
        List<Class> result = getGenericInterfaceTypeArguments(baseInterface, (ParameterizedType)genericInterface, currentTypeParameters);
        if (result != null)
        {
            return result;
        }
    }

    return null;
}
公共类GenericReflectionUtils
{
@抑制警告(“未选中”)
公共静态列表getGenericInterfaceTypeArguments(类baseInterface、类concreteClass)
{
如果(!baseInterface.isAssignableFrom(concreteClass))
{
抛出新的IllegalArgumentException(“非法基接口参数”);
}
if(concreteClass.getTypeParameters().length>0)
{
抛出新的IllegalArgumentException(“无法确定泛型类的泛型接口的类型参数”);
}
对于(类型genericInterface:concreteClass.getGenericInterfaces())
{
列表结果=空;
if(类的通用接口实例)
{
结果=getGenericInterfaceTypeArguments(baseInterface,(类)genericInterface);
}
其他的
{
结果=getGenericInterfaceTypeArguments(baseInterface,(ParameterizedType)genericInterface);
}
如果(结果!=null)
{
返回结果;
}
}
返回null;
}
公共静态类getClass(类型)
{
if(类型instanceof Class)
{
返回(类)类型;
}
if(类型instanceof ParameterizedType)
{
返回getClass(((ParameterizedType)类型).getRawType());
}
if(类型instanceof GenericArrayType)
{
类型componentType=((GenericArrayType)类型).getGenericComponentType();
Class componentClass=getClass(componentType);
if(componentClass!=null)
{
返回Array.newInstance(componentClass,0).getClass();
}
返回null;
}
返回null;
}
@抑制警告(“未选中”)
私有静态列表getGenericInterfaceTypeArguments(类baseInterface,ParameterizedType currentType)
{
Class currentClass=getClass(currentType);
如果(!baseInterface.isAssignableFrom(currentClass))
{
//早期输出-当前类型不是扩展baseInterface的接口
返回null;
}
类型[]actualTypeArguments=currentType.getActualTypeArguments();
if(currentClass==baseInterface)
{
//currentType是基本泛型接口的类型实例。读取类型参数并返回
ArrayList typeArgs=新的ArrayList(actualTypeArguments.length);
for(键入typeArg:actualTypeArguments)
{
add(getClass(typeArg));
}
返回typeArgs;
}
//currentType是派生的
Map-typeVarMap=createTypeParameterMap(currentType,null);
对于(类型genericInterfaceType:currentClass.getGenericInterfaces())
{
列表结果=getGenericInterfaceTypeArguments(baseInterface,(ParameterizedType)genericInterfaceType,typeVarMap);
如果(结果!=null)
{
返回结果;
}
}
返回null;
}
私有静态映射createTypeParameterMap(ParameteredType类型,映射扩展类型映射)
{
Map typeVarMap=newhashmap();
Type[]typeArgs=Type.getActualTypeArguments();
TypeVariable[]typeVars=getClass(type).getTypeParameters();
对于(int-typeArgIndex=0;typeArgIndexpublic class MyClass implements ExtendedInterface<String, Object>, BaseInterface<String>{ }
MyClass.class.getGenericInterfaces()[1].getActualTypeArguments()[0]
public class GenericReflectionUtils
{
@SuppressWarnings("unchecked")
public static List<Class> getGenericInterfaceTypeArguments(Class baseInterface, Class concreteClass)
{
    if (!baseInterface.isAssignableFrom(concreteClass))
    {
        throw new IllegalArgumentException("Illegal base interface argument");
    }
    if (concreteClass.getTypeParameters().length > 0)
    {
        throw new IllegalArgumentException("Can't determine the type arguments of a generic interface of a generic class");
    }
    for (Type genericInterface : concreteClass.getGenericInterfaces())
    {
        List<Class> result = null;
        if (genericInterface instanceof Class)
        {
            result = getGenericInterfaceTypeArguments(baseInterface,(Class)genericInterface);
        }
        else
        {
            result = getGenericInterfaceTypeArguments(baseInterface, (ParameterizedType)genericInterface);
        }
        if (result != null)
        {
            return result;
        }
    }
    return null;
}


public static Class getClass(Type type)
{
    if (type instanceof Class)
    {
        return (Class) type;
    }
    if (type instanceof ParameterizedType)
    {
        return getClass(((ParameterizedType) type).getRawType());
    }
    if (type instanceof GenericArrayType)
    {
        Type componentType = ((GenericArrayType) type).getGenericComponentType();
        Class<?> componentClass = getClass(componentType);
        if (componentClass != null)
        {
            return Array.newInstance(componentClass, 0).getClass();
        }
        return null;
    }
    return null;
}

@SuppressWarnings("unchecked")
private static List<Class> getGenericInterfaceTypeArguments(Class baseInterface, ParameterizedType currentType)
{
    Class currentClass = getClass(currentType);
    if (!baseInterface.isAssignableFrom(currentClass))
    {
        //  Early out - current type is not an interface that extends baseInterface
        return null;
    }

    Type[] actualTypeArguments = currentType.getActualTypeArguments();

    if (currentClass == baseInterface)
    {
        //  currentType is a type instance of the base generic interface. Read out the type arguments and return 
        ArrayList<Class> typeArgs = new ArrayList<Class>(actualTypeArguments.length);
        for (Type typeArg : actualTypeArguments)
        {
            typeArgs.add(getClass(typeArg));
        }

        return typeArgs;
    }

    //  currentType is derived
    Map<String, Class> typeVarMap = createTypeParameterMap(currentType, null);

    for (Type genericInterfaceType : currentClass.getGenericInterfaces())
    {
        List<Class> result = getGenericInterfaceTypeArguments(baseInterface, (ParameterizedType)genericInterfaceType, typeVarMap);
        if (result != null)
        {
            return result;
        }
    }
    return null;
}

private static Map<String, Class> createTypeParameterMap(ParameterizedType type, Map<String, Class> extendedTypeMap)
{
    Map<String, Class> typeVarMap = new HashMap<String, Class>();
    Type[] typeArgs = type.getActualTypeArguments();
    TypeVariable[] typeVars = getClass(type).getTypeParameters();
    for (int typeArgIndex = 0; typeArgIndex < typeArgs.length; ++typeArgIndex)
    {
        //  Does not deal with nested generic arguments...
        Type typeArg = typeArgs[typeArgIndex];
        if (typeArg instanceof TypeVariable)
        {
            assert extendedTypeMap != null;
            TypeVariable typeVar = (TypeVariable)typeArg;
            typeVarMap.put(typeVars[typeArgIndex].getName(), extendedTypeMap.get(typeVar.getName()));
            continue;
        }
        typeVarMap.put(typeVars[typeArgIndex].getName(), getClass(typeArgs[typeArgIndex]));
    }

    return typeVarMap;
}

private static List<Class> createTypeParameterList(Map<String, Class> typeParameterMap, ParameterizedType type)
{
    ArrayList<Class> typeParameters = new ArrayList<Class>(typeParameterMap.size());
    for (Type actualType : type.getActualTypeArguments())
    {
        if (actualType instanceof TypeVariable)
        {
            //  Handles the case when an interface is created with a specific type, rather than a parameter
            typeParameters.add(typeParameterMap.get(((TypeVariable)actualType).getName()));
            continue;
        }
        typeParameters.add(getClass(actualType));
    }
    return typeParameters;
}

@SuppressWarnings("unchecked")
private static List<Class> getGenericInterfaceTypeArguments(Class baseInterface, ParameterizedType currentType, Map<String, Class> currentTypeParameters)
{
    Class currentClass = getClass(currentType);
    if (!baseInterface.isAssignableFrom(currentClass))
    {
        //  Early out - current type is not an interface that extends baseInterface
        return null;
    }

    if (currentClass == baseInterface)
    {
        return createTypeParameterList(currentTypeParameters, currentType);
    }

    currentTypeParameters = createTypeParameterMap(currentType, currentTypeParameters);
    for (Type genericInterface : currentClass.getGenericInterfaces())
    {
        List<Class> result = getGenericInterfaceTypeArguments(baseInterface, (ParameterizedType)genericInterface, currentTypeParameters);
        if (result != null)
        {
            return result;
        }
    }

    return null;
}
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.ParameterizedType;
import java.util.*;

interface BaseInterface<T> {}
interface FirstArg<T1,T2> extends BaseInterface<T1>{}
interface SecondArg<T1,T2> extends BaseInterface<T2>{}

class First implements FirstArg<Number, String> {}
class Second implements SecondArg<Number, String> {}


public class Example {
    public static void main(String[] av) {
        new Example().go();
    }

    void go() {
        test(First.class);
        test(Second.class);
    }

    void test(Class<?> c1) {        
        ParameterizedType t2 = (ParameterizedType) c1.getGenericInterfaces()[0];
        System.out.println(c1 + " implements " + t2 );

        Class<?> c2 = (Class<?>)t2.getRawType();
        GenericDeclaration g2 = (GenericDeclaration) c2;

        System.out.println(t2 + "  params are " + Arrays.asList(g2.getTypeParameters()));

        System.out.println("So that means");
        for(int i = 0; i<t2.getActualTypeArguments().length; i++) {
            System.out.println("Parameter " + c2.getTypeParameters()[i] + " is " + t2.getActualTypeArguments()[i]);
        }

        ParameterizedType t3 =  (ParameterizedType) c2.getGenericInterfaces()[0];
        System.out.println(t2 + "  implements " + t3);

        System.out.println("and so that means we are talking about\n" + t3.getRawType().toString() + " <");
        for(int i = 0 ; i< t3.getActualTypeArguments().length; i++) {
            System.out.println("\t" + t3.getActualTypeArguments()[i] + " -> " 
            + Arrays.asList(g2.getTypeParameters()).indexOf(t3.getActualTypeArguments()[i])
            + " -> " + 
            t2.getActualTypeArguments()[Arrays.asList(g2.getTypeParameters()).indexOf(t3.getActualTypeArguments()[i])]
            );
        }

        System.out.println(">");
        System.out.println();
    }

}
Type myType = MyClass.class;

// get the parameterized type, recursively resolving type parameters
Type baseType = GenericTypeReflector.getExactSuperType(myType, BaseInterface.class);

if (baseType instanceof Class<?>) {
    // raw class, type parameters not known
    // ...
} else {
    ParameterizedType pBaseType = (ParameterizedType)baseType;
    assert pBaseType.getRawType() == BaseInterface.class; // always true
    Type typeParameterForBaseInterface = pBaseType.getActualTypeArguments()[0];
    System.out.println(typeParameterForBaseInterface);
}
TypeToken<? extends T> token = TypeToken.of(MyClass.class);
ParameterizedType type =
    (ParameterizedType) token.getSupertype(BaseInterface.class).getType();
Type[] parameters = type.getActualTypeArguments();