java.lang.reflect.Type 是 Java 反射系统中的一个核心接口,它是所有类型的公共父接口,用于在运行时表明 Java 中的各种类型,包括:
- 原始类型(如 String.class)
- 参数化类型(如 List<String>)
- 泛型数组类型(如 T[])
- 类型变量(如 <T>)
- 通配符类型(如 ? extends Number)
一、为什么需要 Type?
Java 的泛型是通过类型擦除(Type Erasure)实现的:
List<String> list = new ArrayList<>();
在运行时,list.getClass() 返回的是 ArrayList.class,泛型信息 String 被擦除了。
但 Type 可以保留这些泛型信息!它让你在反射中知道:
“这个字段的类型是 List<String>,而不仅仅是 List。”
二、Type的继承体系
Type 是一个标记接口,有以下几个重大子接口:
Type
├── Class<T> // 原始类型,如 String, int ,枚举,注解,数组
├── ParameterizedType // 参数化类型,如 Map<String, Integer>
├── GenericArrayType // 泛型数组,如 T[], List<String>[]
├── WildcardType // 通配符类型,如 ? extends Number, ? super T
└── TypeVariable<D> // 类型变量,如 <T>, <E extends Comparable<E>>
✅ 所有这些都实现了 Type 接口。接口能力getTypeName()
三、核心子接口详解与示例
1. ParameterizedType—— 参数化类型
表明一个带有具体或抽象类型参数的泛型类型,例如:List<String>、Map<K, V>、Set<T[]> 等。
示例:获取字段的泛型信息
import java.lang.reflect.*;
import java.util.List;
import java.util.Map;
public class TypeExample {
private List<String> names;
private Map<Integer, String> data;
public static void main(String[] args) throws Exception {
Field field = TypeExample.class.getDeclaredField("names");
Type genericType = field.getGenericType(); // 返回 Type
if (genericType instanceof ParameterizedType pt) {
System.out.println("主类型: " + pt.getRawType()); // List
Type[] typeArgs = pt.getActualTypeArguments();
System.out.println("泛型参数: " + Arrays.toString(typeArgs)); // [class java.lang.String]
}
}
}
2. GenericArrayType—— 泛型数组
GenericArrayType 是 Java 反射 API 中 java.lang.reflect.Type 接口的一个子接口,它不用于普通数组(如 String[]、int[]),而是用于表明组件类型为参数化类型或类型变量的数组。实现它的主要是 JVM 在运行时动态生成的类型对象。
什么时候会用到 GenericArrayType?
当你有一个数组,它的元素是以下之一:
- 类型变量:T[]
- 参数化类型:List<String>[], Map<K, V>[]
这时,通过反射获取该字段的 getGenericType(),就会得到一个 GenericArrayType。
实际代码示例
示例 1:T[]数组(类型变量数组)
public class ArrayHolder<T> {
T[] values; // T[] → 元素是类型变量
}
Field field = ArrayHolder.class.getDeclaredField("values");
Type genericType = field.getGenericType();
if (genericType instanceof GenericArrayType) {
GenericArrayType gat = (GenericArrayType) genericType;
System.out.println("数组类型: " + gat);
// 输出: T[]
Type componentType = gat.getGenericComponentType();
// 得到 T(这是一个 TypeVariable)
if (componentType instanceof TypeVariable) {
TypeVariable<?> tv = (TypeVariable<?>) componentType;
System.out.println("组件类型是类型变量: " + tv.getName()); // T
System.out.println("声明该变量的类: " + tv.getGenericDeclaration()); // class ArrayHolder
}
}
示例 2:List<String>[](参数化类型的数组)
public class DataContainer {
List<String>[] stringLists; // List<String>[]
}
Field field = DataContainer.class.getDeclaredField("stringLists");
Type genericType = field.getGenericType();
if (genericType instanceof GenericArrayType) {
GenericArrayType gat = (GenericArrayType) genericType;
System.out.println("数组类型: " + gat);
// 输出: java.util.List<java.lang.String>[]
Type componentType = gat.getGenericComponentType();
// 得到 List<String>(这是一个 ParameterizedType)
if (componentType instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) componentType;
System.out.println("组件类型原始类: " + pt.getRawType()); // interface java.util.List
System.out.println("泛型参数: " + Arrays.toString(pt.getActualTypeArguments())); // [class java.lang.String]
}
}
普通数组不会产生 GenericArrayType
String[] names;
int[] numbers;
List rawListArray[];
这些虽然也是数组,但它们的“组件类型”不是泛型或类型变量:
- String[] → 组件类型是 String.class(Class<String>)
- int[] → 组件类型是 int.class
- List[] → 组件类型是 List.class(原始类型)
所以它们的 getGenericType() 返回的是 Class 类型,不是 GenericArrayType。
GenericArrayType接口的方法
public interface GenericArrayType extends Type {
// 获取这个数组的“组件类型”
// 例如:对于 T[],返回 T(可能是 TypeVariable 或 ParameterizedType)
Type getGenericComponentType();
}
这是它唯一的接口方法,但超级关键。
常见误区
|
错误理解 |
正确理解 |
|
所有数组都是 GenericArrayType |
只有组件类型是泛型的才是 |
|
List<String>[] 不能被反射识别 |
可以,它是 GenericArrayType |
|
GenericArrayType 有 .class 对象 |
它是运行时由 JVM 构造的,不能直接 new 或 .class |
|
new ArrayList<String>[10] 合法 |
Java 不允许创建泛型数组实例(编译错误) |
提示:Java 不允许你写 new List<String>[10](编译时报错),但在类型声明中可以存在 List<String>[],这就是 GenericArrayType 的用途 —— 描述这种“理论上存在但无法实例化”的类型。
3. WildcardType—— 通配符类型
表明 ? 类型,如 ? extends Number、? super T。
public class WildcardExample {
List<? extends Number> numbers;
List<? super String> objects;
}
Field field = WildcardExample.class.getDeclaredField("numbers");
ParameterizedType pt = (ParameterizedType) field.getGenericType();
Type wildcard = pt.getActualTypeArguments()[0];
if (wildcard instanceof WildcardType wt) {
System.out.println("上界: " + Arrays.toString(wt.getUpperBounds())); // Number
System.out.println("下界: " + Arrays.toString(wt.getLowerBounds())); // []
}
4. TypeVariable—— 类型变量
表明泛型声明中的 <T>、<E> 等。
public class Box<T> {
T content;
}
Field field = Box.class.getDeclaredField("content");
Type type = field.getGenericType();
if (type instanceof TypeVariable<?> tv) {
System.out.println("名称: " + tv.getName()); // T
System.out.println("声明类: " + tv.getGenericDeclaration()); // class Box
}
五、如何获取 Type?
|
方式 |
方法 |
|
字段泛型信息 |
field.getGenericType() |
|
方法参数泛型信息 |
method.getGenericParameterTypes() |
|
方法返回值泛型信息 |
method.getGenericReturnType() |
|
类泛型信息 |
clazz.getGenericSuperclass() 或 clazz.getGenericInterfaces() 或 clazz.getTypeParameters() |
收藏了,感谢分享