Get generic type of class at runtime

后端 未结 26 3215
野的像风
野的像风 2020-11-21 04:40

How can I achieve this?

public class GenericClass
{
    public Type getMyType()
    {
        //How do I return the type of T?
    }
}
26条回答
  •  日久生厌
    2020-11-21 05:07

    Here is my solution. The examples should explain it. The only requirement is that a subclass must set the generic type, not an object.

    import java.lang.reflect.AccessibleObject;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    import java.lang.reflect.TypeVariable;
    import java.util.HashMap;
    import java.util.Map;
    
    public class TypeUtils {
    
        /*** EXAMPLES ***/
    
        public static class Class1 {
    
            public A someA;
            public B someB;
            public C someC;
    
            public Class getAType() {
                return getTypeParameterType(this.getClass(), Class1.class, 0);
            }
    
            public Class getCType() {
                return getTypeParameterType(this.getClass(), Class1.class, 2);
            }
        }
    
        public static class Class2 extends Class1 {
    
            public B someB;
            public D someD;
            public E someE;
        }
    
        public static class Class3 extends Class2 {
    
            public E someE;
        }
    
        public static class Class4 extends Class3 {
    
        }
    
        public static void test() throws NoSuchFieldException {
    
            Class4 class4 = new Class4();
            Class typeA = class4.getAType(); // typeA = Integer
            Class typeC = class4.getCType(); // typeC = Long
    
            Field fieldSomeA = class4.getClass().getField("someA");
            Class typeSomeA = TypeUtils.getFieldType(class4.getClass(), fieldSomeA); // typeSomeA = Integer
    
            Field fieldSomeE = class4.getClass().getField("someE");
            Class typeSomeE = TypeUtils.getFieldType(class4.getClass(), fieldSomeE); // typeSomeE = Boolean
    
    
        }
    
        /*** UTILS ***/
    
        public static Class getTypeVariableType(Class subClass, TypeVariable typeVariable) {
            Map, Type> subMap = new HashMap<>();
            Class superClass;
            while ((superClass = subClass.getSuperclass()) != null) {
    
                Map, Type> superMap = new HashMap<>();
                Type superGeneric = subClass.getGenericSuperclass();
                if (superGeneric instanceof ParameterizedType) {
    
                    TypeVariable[] typeParams = superClass.getTypeParameters();
                    Type[] actualTypeArgs = ((ParameterizedType) superGeneric).getActualTypeArguments();
    
                    for (int i = 0; i < typeParams.length; i++) {
                        Type actualType = actualTypeArgs[i];
                        if (actualType instanceof TypeVariable) {
                            actualType = subMap.get(actualType);
                        }
                        if (typeVariable == typeParams[i]) return (Class) actualType;
                        superMap.put(typeParams[i], actualType);
                    }
                }
                subClass = superClass;
                subMap = superMap;
            }
            return null;
        }
    
        public static Class getTypeParameterType(Class subClass, Class superClass, int typeParameterIndex) {
            return TypeUtils.getTypeVariableType(subClass, superClass.getTypeParameters()[typeParameterIndex]);
        }
    
        public static Class getFieldType(Class clazz, AccessibleObject element) {
            Class type = null;
            Type genericType = null;
    
            if (element instanceof Field) {
                type = ((Field) element).getType();
                genericType = ((Field) element).getGenericType();
            } else if (element instanceof Method) {
                type = ((Method) element).getReturnType();
                genericType = ((Method) element).getGenericReturnType();
            }
    
            if (genericType instanceof TypeVariable) {
                Class typeVariableType = TypeUtils.getTypeVariableType(clazz, (TypeVariable) genericType);
                if (typeVariableType != null) {
                    type = typeVariableType;
                }
            }
    
            return type;
        }
    
    }
    

提交回复
热议问题