Java泛型字段类型解析与Spring实现

小豆丁 昨天 ⋅ 20 阅读
聊天记录
头像

// 关键:获取字段的声明类型 Type fieldType = field.getGenericType(); // 这是泛型类型 M

        // 步骤4: 解析字段的实际类型
        // fieldType 是 TypeVariable,名称为 "M"
        // 但结合当前类的泛型上下文,M 对应 typeArgs[0] = UserMapper.class
        
        Class<?> actualFieldType = resolveActualType(fieldType, typeArgs);
        // 返回 UserMapper.class    getGenericType(); 这里可以获取泛型字段的实际类型是吧?
头像

不,你说对了一半!getGenericType() 返回的是字段的声明类型,但如果是泛型字段,它返回的是类型变量(TypeVariable),而不是具体的实际类型。让我详细解释:

1. getGenericType() 的真实行为

JAVA
public abstract class BaseRepository<M extends BaseMapper<T>, T> {
    protected M baseMapper;  // 字段声明为泛型类型 M
}

// 测试代码
Field field = BaseRepository.class.getDeclaredField("baseMapper");

// 1. 获取字段的普通类型
Class<?> fieldClass = field.getType();
System.out.println("getType(): " + fieldClass.getName());
// 输出: BaseMapper   ← 这是类型擦除后的类型

// 2. 获取字段的泛型类型
Type genericType = field.getGenericType();
System.out.println("getGenericType(): " + genericType);
// 输出: M   ← 返回的是类型变量,不是具体类型!

System.out.println("genericType instanceof TypeVariable: " + 
                   (genericType instanceof TypeVariable));
// 输出: true

2. 为什么 getGenericType() 返回 TypeVariable

在 BaseRepository 类中:

JAVA
// 源代码
public abstract class BaseRepository<M extends BaseMapper<T>, T> {
    protected M baseMapper;  // 这里 M 是类型变量
}

// 编译后的字节码中,这个字段的签名为:
// Signature: M;  // 表示类型变量 M

所以:

JAVA
// 在 BaseRepository 层面,只知道 baseMapper 是类型 M
// 不知道 M 具体是什么
Type fieldType = field.getGenericType();  // 返回 TypeVariable "M"

3. 如何获取具体的实际类型

要获取字段在具体子类中的实际类型,需要结合子类的泛型信息

JAVA
// 完整示例
import java.lang.reflect.*;

public class GenericFieldResolution {
    
    public static void main(String[] args) throws Exception {
        // 获取字段
        Field field = BaseRepository.class.getDeclaredField("baseMapper");
        
        // 方法1:在BaseRepository层面获取(只有类型变量)
        System.out.println("=== 在BaseRepository层面 ===");
        Type genericType = field.getGenericType();
        System.out.println("字段泛型类型: " + genericType);
        System.out.println("是否是TypeVariable: " + (genericType instanceof TypeVariable));
        
        if (genericType instanceof TypeVariable) {
            TypeVariable<?> typeVar = (TypeVariable<?>) genericType;
            System.out.println("类型变量名称: " + typeVar.getName());
            System.out.println("类型变量边界: " + 
                java.util.Arrays.toString(typeVar.getBounds()));
        }
        
        // 方法2:在UserRepository层面获取(具体类型)
        System.out.println("\n=== 在UserRepository层面 ===");
        Class<?> actualType = resolveFieldTypeInSubclass(
            UserRepository.class, "baseMapper");
        System.out.println("实际类型: " + actualType);
    }
    
    /**
     * 解析字段在子类中的实际类型
     */
    public static Class<?> resolveFieldTypeInSubclass(
            Class<?> subclass, String fieldName) throws Exception {
        
        // 1. 获取字段
        Field field = getFieldInHierarchy(subclass, fieldName);
        
        // 2. 获取子类的泛型信息
        Type genericSuperclass = subclass.getGenericSuperclass();
        
        if (genericSuperclass instanceof ParameterizedType) {
            ParameterizedType paramType = (ParameterizedType) genericSuperclass;
            
            // 3. 获取字段的泛型类型
            Type fieldGenericType = field.getGenericType();
            
            if (fieldGenericType instanceof TypeVariable) {
                TypeVariable<?> typeVar = (TypeVariable<?>) fieldGenericType;
                
                // 4. 获取父类的类型参数
                TypeVariable<?>[] typeParams = 
                    ((Class<?>) paramType.getRawType()).getTypeParameters();
                Type[] actualTypes = paramType.getActualTypeArguments();
                
                // 5. 建立映射
                for (int i = 0; i < typeParams.length; i++) {
                    if (typeParams[i].getName().equals(typeVar.getName())) {
                        // 找到对应的实际类型
                        Type actualType = actualTypes[i];
                        
                        if (actualType instanceof Class) {
                            return (Class<?>) actualType;
                        } else if (actualType instanceof ParameterizedType) {
                            return (Class<?>) ((ParameterizedType) actualType).getRawType();
                        }
                    }
                }
            }
        }
        
        return null;
    }
    
    private static Field getFieldInHierarchy(Class<?> clazz, String fieldName) 
            throws NoSuchFieldException {
        Class<?> current = clazz;
        while (current != null && current != Object.class) {
            try {
                Field field = current.getDeclaredField(fieldName);
                field.setAccessible(true);
                return field;
            } catch (NoSuchFieldException e) {
                current = current.getSuperclass();
            }
        }
        throw new NoSuchFieldException(fieldName);
    }
}

4. Spring 的实现方式

Spring 通过 ResolvableType 来简化这个过程:

JAVA
import org.springframework.core.ResolvableType;

public class SpringResolvableTypeExample {
    
    public static void main(String[] args) throws Exception {
        // 获取字段
        Field field = BaseRepository.class.getDeclaredField("baseMapper");
        
        // 1. 在BaseRepository层面
        ResolvableType fieldType = ResolvableType.forField(field);
        System.out.println("字段的ResolvableType: " + fieldType);
        System.out.println("解析出的类型: " + fieldType.resolve());
        // 输出: null 或 BaseMapper(边界类型)
        
        // 2. 在UserRepository层面
        ResolvableType fieldTypeInContext = 
            ResolvableType.forField(field, UserRepository.class);
        System.out.println("\n在UserRepository上下文中的字段类型: " + fieldTypeInContext);
        System.out.println("解析出的实际类型: " + fieldTypeInContext.resolve());
        // 输出: UserMapper.class
    }
}

5. 完整的演示代码

JAVA
import java.lang.reflect.*;
import org.springframework.core.ResolvableType;

// 定义测试类
class BaseMapper<T> {}
class UserMapper extends BaseMapper<User> {}
class User {}

abstract class BaseRepository<M extends BaseMapper<T>, T> {
    protected M baseMapper;
}

class UserRepository extends BaseRepository<UserMapper, User> {}

public class GenericTypeExample {
    
    public static void main(String[] args) throws Exception {
        System.out.println("=== 演示1: 基本反射 ===");
        demoBasicReflection();
        
        System.out.println("\n=== 演示2: Spring ResolvableType ===");
        demoSpringResolvableType();
        
        System.out.println("\n=== 演示3: 完整解析过程 ===");
        demoFullResolution();
    }
    
    static void demoBasicReflection() throws Exception {
        Field field = BaseRepository.class.getDeclaredField("baseMapper");
        
        // 1. 获取字段的普通类型(类型擦除后)
        System.out.println("field.getType(): " + field.getType().getName());
        // 输出: BaseMapper
        
        // 2. 获取字段的泛型类型声明
        Type genericType = field.getGenericType();
        System.out.println("field.getGenericType(): " + genericType);
        // 输出: M
        
        // 3. 查看泛型类型详情
        if (genericType instanceof TypeVariable) {
            TypeVariable<?> tv = (TypeVariable<?>) genericType;
            System.out.println("类型变量名称: " + tv.getName());
            System.out.println("类型变量边界: " + 
                java.util.Arrays.toString(tv.getBounds()));
            // 输出: 名称: M, 边界: [BaseMapper<T>]
            
            // 获取声明此类型变量的类
            GenericDeclaration decl = tv.getGenericDeclaration();
            System.out.println("声明位置: " + decl);
            // 输出: class BaseRepository
        }
    }
    
    static void demoSpringResolvableType() throws Exception {
        Field field = BaseRepository.class.getDeclaredField("baseMapper");
        
        // 1. 在BaseRepository类上下文中
        ResolvableType fieldType = ResolvableType.forField(field);
        System.out.println("在BaseRepository中:");
        System.out.println("  ResolvableType: " + fieldType);
        System.out.println("  resolve(): " + fieldType.resolve());
        // 输出: BaseMapper(边界类型)
        
        // 2. 在UserRepository类上下文中
        ResolvableType fieldTypeInContext = 
            ResolvableType.forField(field, UserRepository.class);
        System.out.println("\n在UserRepository中:");
        System.out.println("  ResolvableType: " + fieldTypeInContext);
        System.out.println("  resolve(): " + fieldTypeInContext.resolve());
        // 输出: UserMapper
        
        // 3. 获取泛型参数
        if (fieldTypeInContext.hasGenerics()) {
            ResolvableType[] generics = fieldTypeInContext.getGenerics();
            System.out.println("  泛型参数: ");
            for (int i = 0; i < generics.length; i++) {
                System.out.println("    " + i + ": " + generics[i].resolve());
            }
            // 输出: 0: User
        }
    }
    
    static void demoFullResolution() throws Exception {
        // 模拟Spring注入时的类型解析
        
        // 1. 获取子类的泛型父类
        Class<?> clazz = UserRepository.class;
        Type genericSuperclass = clazz.getGenericSuperclass();
        
        if (genericSuperclass instanceof ParameterizedType) {
            ParameterizedType paramType = (ParameterizedType) genericSuperclass;
            
            // 2. 获取实际类型参数
            Type[] actualTypes = paramType.getActualTypeArguments();
            System.out.println("UserRepository的实际类型参数:");
            for (int i = 0; i < actualTypes.length; i++) {
                System.out.println("  " + i + ": " + actualTypes[i]);
            }
            // 输出: 0: UserMapper, 1: User
            
            // 3. 获取字段
            Field field = BaseRepository.class.getDeclaredField("baseMapper");
            Type fieldGenericType = field.getGenericType();
            
            if (fieldGenericType instanceof TypeVariable) {
                TypeVariable<?> typeVar = (TypeVariable<?>) fieldGenericType;
                
                // 4. 获取父类的类型参数
                TypeVariable<?>[] typeParams = 
                    ((Class<?>) paramType.getRawType()).getTypeParameters();
                
                // 5. 建立映射
                for (int i = 0; i < typeParams.length; i++) {
                    if (typeParams[i].getName().equals(typeVar.getName())) {
                        System.out.println("\n字段 baseMapper 的类型变量 " + 
                            typeVar.getName() + " 对应第 " + i + " 个参数");
                        System.out.println("实际类型: " + actualTypes[i]);
                        break;
                    }
                }
            }
        }
    }
}

6. 输出结果示例

=== 演示1: 基本反射 ===
field.getType(): BaseMapper
field.getGenericType(): M
类型变量名称: M
类型变量边界: [BaseMapper<T>]
声明位置: class BaseRepository

=== 演示2: Spring ResolvableType ===
在BaseRepository中:
  ResolvableType: M
  resolve(): BaseMapper
在UserRepository中:
  ResolvableType: UserMapper
  resolve(): UserMapper
  泛型参数: 
    0: User

=== 演示3: 完整解析过程 ===
UserRepository的实际类型参数:
  0: UserMapper
  1: User
字段 baseMapper 的类型变量 M 对应第 0 个参数
实际类型: UserMapper

7. 关键总结

  1. field.getType():返回类型擦除后的类,如 BaseMapper.class

  2. field.getGenericType():返回声明时的泛型类型

    • 如果是泛型字段,返回 TypeVariable(如 "M")
    • 如果是参数化类型,返回 ParameterizedType(如 List&lt;String&gt;
    • 如果是普通类,返回 Class
  3. 单独使用 getGenericType() 无法知道实际类型,必须结合具体的子类上下文

  4. Spring 通过 ResolvableType.forField(field, contextClass) 来获取字段在特定上下文中的实际类型

8. Spring 注入时的完整流程

JAVA
// Spring 实际注入的简化版本
public class SpringInjector {
    
    public void injectField(Object bean, Field field, BeanFactory beanFactory) {
        // 1. 获取字段在具体bean类中的实际类型
        ResolvableType fieldType = ResolvableType.forField(field, bean.getClass());
        
        // 2. 解析实际类型
        Class<?> requiredType = fieldType.resolve();
        
        // 3. 从容器中获取Bean
        Object dependency = beanFactory.getBean(requiredType);
        
        // 4. 注入
        field.setAccessible(true);
        field.set(bean, dependency);
    }
}

所以,直接调用 field.getGenericType() 只能得到声明时的类型变量 "M",要得到具体的 UserMapper.class,必须结合子类 UserRepository 的泛型信息进行解析。

全部评论: 0

    我有话说: