0%

反射之Type类

Java 中 Type 接口体系详解:解析泛型类型的核心

在 Java 反射中,Type 接口是所有类型的父接口,它不仅包含我们熟悉的原始类型(如 StringInteger),还涵盖了泛型相关的复杂类型(如 List<String>T? extends Number 等)。理解 Type 体系是处理泛型反射的关键,尤其在框架开发(如 JSON 反序列化、ORM 映射)中频繁用到。本文将详细解析 Type 接口的子类型及其应用场景。

Type 接口体系概览

Type 接口是 Java 1.5 引入的,用于统一表示所有类型,包括:

  • 原始类型(如 Class 表示的 Stringint);
  • 泛型相关类型(参数化类型、类型变量、通配符类型等)。

其体系结构如下:

Type 各子类型详解

Class:原始类型的实现类

ClassType 接口的唯一实现类,用于表示原始类型(非泛型类型),包括:

  • 基本数据类型(如 int.classboolean.class);
  • 普通类 / 接口 / 枚举(如 String.classList.classEnum.class);
  • 数组类型(如 int[].classString[].class,但不包括泛型数组)。

示例

1
2
3
4
5
6
7
// 原始类型
Class<String> stringClass = String.class;
Class<Integer> intClass = Integer.class;
Class<int[]> intArrayClass = int[].class;

// 判断是否为原始类型
System.out.println(stringClass instanceof Type); // true(Class 实现了 Type)

应用场景:判断对象的具体类型(如 obj.getClass())、反射中获取类的元数据。

ParameterizedType:参数化类型(带泛型的类型)

ParameterizedType 表示带有具体泛型参数的类型,即我们日常使用的 List<String>Map<String, Integer> 等。它的核心是 “原始类型 + 具体泛型参数” 的组合。

核心方法:
  • Type getRawType():返回原始类型(泛型的 “模板类”)。例如 List<String> 的原始类型是 List.class
  • Type[] getActualTypeArguments():返回具体的泛型参数列表。例如 Map<String, Integer> 的参数列表是 [String.class, Integer.class]
  • Type getOwnerType():返回类型的 “所有者类型”(仅用于内部类)。例如 Map.Entry<String, Integer> 的所有者类型是 Map.class

示例解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 定义一个带泛型的字段
public class TypeDemo {
private List<String> stringList;
private Map<String, Integer> stringIntMap;
private Map.Entry<Integer, String> entry;
}

// 通过反射获取 ParameterizedType
public static void main(String[] args) throws NoSuchFieldException {
// 1. 获取 stringList 字段的类型
Field listField = TypeDemo.class.getDeclaredField("stringList");
ParameterizedType listType = (ParameterizedType) listField.getGenericType();

System.out.println(listType.getRawType()); // class java.util.List(原始类型)
System.out.println(Arrays.toString(listType.getActualTypeArguments())); // [class java.lang.String](泛型参数)

// 2. 获取 entry 字段的类型(内部类的所有者类型)
Field entryField = TypeDemo.class.getDeclaredField("entry");
ParameterizedType entryType = (ParameterizedType) entryField.getGenericType();
System.out.println(entryType.getOwnerType()); // interface java.util.Map(所有者类型)
}

TypeVariable:类型变量(泛型中的占位符)

TypeVariable 表示泛型中的类型变量,即 <T><K, V> 中的 TKV,它们是泛型定义时的 “占位符”,在使用时会被具体类型替换。

核心方法:
  • Type[] getBounds():返回类型变量的上边界(默认上边界为 Object)。例如 <T extends Number>T 的上边界是 Number.class
  • Type getGenericDeclaration():返回声明该类型变量的原始类型。例如 class MyClass<T> 中,T 的声明类型是 MyClass.class
  • String getName():返回类型变量在源码中的名称(如 TK)。

示例解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 定义带类型变量的类
class MyClass<T extends Number & Serializable, V> {
private T t;
private V v;
}

// 通过反射获取 TypeVariable
public static void main(String[] args) {
// 获取 MyClass 的泛型参数(TypeVariable 数组)
TypeVariable<? extends Class<MyClass>>[] typeVariables = MyClass.class.getTypeParameters();

// 解析第一个类型变量 T
TypeVariable<? extends Class<MyClass>> tVar = typeVariables[0];
System.out.println(tVar.getName()); // T(名称)
System.out.println(Arrays.toString(tVar.getBounds())); // [class java.lang.Number, interface java.io.Serializable](上边界)
System.out.println(tVar.getGenericDeclaration()); // class MyClass(声明类型)

// 解析第二个类型变量 V(默认上边界为 Object)
TypeVariable<? extends Class<MyClass>> vVar = typeVariables[1];
System.out.println(Arrays.toString(vVar.getBounds())); // [class java.lang.Object]
}

GenericArrayType:泛型数组类型

GenericArrayType 表示元素类型为泛型的数组,即数组的元素是 ParameterizedTypeTypeVariable。例如 T[]List<String>[]Map<K, V>[] 等(注意:int[]String[] 是普通数组,对应 Class 类型)。

核心方法:
  • Type getGenericComponentType():返回数组的元素类型(泛型类型)。例如 List<String>[] 的元素类型是 List<String>ParameterizedType)。

示例解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class TypeDemo {
private List<String>[] listArray; // 泛型数组(GenericArrayType)
private T[] tArray; // 泛型数组(GenericArrayType)
private String[] strArray; // 普通数组(Class)
}

public static void main(String[] args) throws NoSuchFieldException {
// 1. 解析 listArray 字段(List<String>[])
Field listArrayField = TypeDemo.class.getDeclaredField("listArray");
GenericArrayType listArrayType = (GenericArrayType) listArrayField.getGenericType();
System.out.println(listArrayType.getGenericComponentType()); // java.util.List<String>(元素类型)

// 2. 解析 tArray 字段(T[])
Field tArrayField = TypeDemo.class.getDeclaredField("tArray");
GenericArrayType tArrayType = (GenericArrayType) tArrayField.getGenericType();
System.out.println(tArrayType.getGenericComponentType()); // T(元素类型,TypeVariable)

// 3. 普通数组是 Class 类型,不是 GenericArrayType
Field strArrayField = TypeDemo.class.getDeclaredField("strArray");
System.out.println(strArrayField.getGenericType() instanceof Class); // true
}

WildcardType:通配符类型(? 相关类型)

WildcardType 表示通配符泛型,即 ?? extends Number? super Integer 中的 ?,用于限制泛型的取值范围。

核心方法:
  • Type[] getUpperBounds():返回通配符的上边界。例如 ? extends Number 的上边界是 Number.class(默认上边界为 Object)。
  • Type[] getLowerBounds():返回通配符的下边界。例如 ? super Integer 的下边界是 Integer.class(默认下边界为空)。

示例解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class TypeDemo {
private List<? extends Number> upperList; // 上边界通配符
private List<? super Integer> lowerList; // 下边界通配符
private List<?> anyList; // 无边界通配符(默认上边界为 Object)
}

public static void main(String[] args) throws NoSuchFieldException {
// 1. 解析 upperList 字段(? extends Number)
Field upperField = TypeDemo.class.getDeclaredField("upperList");
ParameterizedType upperPt = (ParameterizedType) upperField.getGenericType();
WildcardType upperWildcard = (WildcardType) upperPt.getActualTypeArguments()[0];
System.out.println(Arrays.toString(upperWildcard.getUpperBounds())); // [class java.lang.Number]
System.out.println(Arrays.toString(upperWildcard.getLowerBounds())); // [](无下边界)

// 2. 解析 lowerList 字段(? super Integer)
Field lowerField = TypeDemo.class.getDeclaredField("lowerList");
ParameterizedType lowerPt = (ParameterizedType) lowerField.getGenericType();
WildcardType lowerWildcard = (WildcardType) lowerPt.getActualTypeArguments()[0];
System.out.println(Arrays.toString(lowerWildcard.getLowerBounds())); // [class java.lang.Integer]
System.out.println(Arrays.toString(lowerWildcard.getUpperBounds())); // [class java.lang.Object](默认上边界)
}

Type 体系的典型应用场景

Type 体系在需要处理泛型反射的场景中必不可少,以下是几个典型案例:

JSON 反序列化(如 Gson、Jackson)

JSON 框架需要将 JSON 字符串转换为泛型对象(如 List<User>),需通过 ParameterizedType 获取具体泛型参数(User.class):

1
2
3
// Gson 中获取 List<User> 类型
Type type = new TypeToken<List<User>>(){}.getType();
List<User> users = new Gson().fromJson(json, type);

TypeToken 内部通过 getGenericSuperclass() 获取父类的 ParameterizedType,从而解析出 List<User> 中的 User

ORM 框架映射(如 MyBatis)

MyBatis 在映射 List<User> 等泛型返回值时,需通过 ParameterizedType 确定集合中的元素类型(User),以便正确映射数据库记录。

泛型工具类开发

在开发通用泛型工具(如集合工具、缓存工具)时,需通过 Type 体系判断参数的泛型类型,实现更灵活的逻辑:

1
2
3
4
5
6
7
8
9
// 判断一个类型是否为 List<String>
public static boolean isListOfString(Type type) {
if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type;
return pt.getRawType() == List.class
&& pt.getActualTypeArguments()[0] == String.class;
}
return false;
}

欢迎关注我的其它发布渠道

表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10