Đây là giải pháp của tôi. Các ví dụ nên giải thích nó. Yêu cầu duy nhất là một lớp con phải đặt loại chung, không phải là một đối tượng.
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<A, B, C> {
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<D, A, B, E, C> extends Class1<A, B, C> {
public B someB;
public D someD;
public E someE;
}
public static class Class3<E, C> extends Class2<String, Integer, Double, E, C> {
public E someE;
}
public static class Class4 extends Class3<Boolean, Long> {
}
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<TypeVariable<?>, Type> subMap = new HashMap<>();
Class<?> superClass;
while ((superClass = subClass.getSuperclass()) != null) {
Map<TypeVariable<?>, 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;
}
}