// 关键:获取字段的声明类型 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. 关键总结
field.getType():返回类型擦除后的类,如BaseMapper.classfield.getGenericType():返回声明时的泛型类型- 如果是泛型字段,返回
TypeVariable(如 "M") - 如果是参数化类型,返回
ParameterizedType(如List<String>) - 如果是普通类,返回
Class
- 如果是泛型字段,返回
单独使用
getGenericType()无法知道实际类型,必须结合具体的子类上下文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 的泛型信息进行解析。