类型元数据分析
1、为什么需要类型分析?
在开发框架时,经常需要在运行时获取泛型的真实类型信息。例如:
- JSON 反序列化时,需要知道
List字段的元素是String还是UserModel - ORM 框架映射查询结果时,需要知道
Map的 Key 和 Value 分别是什么类型 - 依赖注入容器在解析泛型依赖时,需要获取完整的泛型参数信息
Java 的泛型在编译后会被擦除,运行时只能看到原始类型。TypeEggg 通过解析匿名子类的父类签名,在运行时还原泛型信息。
TypeEggg 是 EggG 的两大核心能力之一,它对 java.lang.reflect.Type 进行了统一包装,提供类型判断和泛型信息访问能力。
2、TypeEggg 概述
TypeEggg 提供以下能力:
- 类型识别 — 判断是普通 Class、参数化类型、还是类型变量
- 泛型参数提取 — 获取
Map<K, V>中K → String、V → UserModel等对应关系 - 原始类型获取 — 返回擦除后的
Class对象(默认Object.class) - JDK 类型判断 — 区分业务自定义类型和 JDK 内置类型
3、基本用法
获取 TypeEggg
Eggg eggg = new Eggg();
// 方式一:通过匿名子类保留泛型信息
TypeEggg typeEggg = eggg.getTypeEggg(new HashMap<String, Integer>() {}.getClass());
// 方式二:通过已有的 Type 对象
TypeEggg typeEggg = eggg.getTypeEggg(myType);
原理:Java 的泛型在编译后会被擦除。但创建匿名子类
new HashMap<String, Integer>() {}(注意末尾的{})时,编译器会在其父类签名中保留泛型参数信息,TypeEggg 可以从中解析出完整的泛型类型。
类型判断
TypeEggg 提供一组 isXxx() 方法用于快速判断类型:
TypeEggg t = eggg.getTypeEggg(new ArrayList<String>() {}.getClass());
t.isCollection(); // true
t.isList(); // true
t.isSet(); // false
t.isMap(); // false
t.isArray(); // false
t.isEnum(); // false
t.isPrimitive(); // false
t.isString(); // false
t.isNumber(); // false
t.isBoolean(); // false
t.isObject(); // false
t.isJdkType(); // true
t.isInterface(); // false
t.isAbstract(); // false
泛型信息提取
TypeEggg t = eggg.getTypeEggg(new HashMap<String, UserModel>() {}.getClass());
// 是否为参数化类型
t.isParameterizedType(); // true
// 获取 ParameterizedType
ParameterizedType pt = t.getParameterizedType();
// 获取实际泛型参数
Type[] args = t.getActualTypeArguments();
args[0]; // String.class
args[1]; // UserModel.class
类型分类判断
Java 的类型体系包含多种形态,TypeEggg 对它们都提供了支持:
// 参数化类型:List<String>、Map<String, Integer>
t.isParameterizedType();
t.getParameterizedType();
t.getActualTypeArguments();
// 类型变量:T、E 等
t.isTypeVariable();
t.getTypeVariable();
// 通配符类型:? extends Number、? super String
t.isWildcardType();
t.getWildcardType();
// 泛型数组类型:T[]、List<String>[]
t.isGenericArrayType();
t.getGenericArrayType();
获取原始类型
// 获取擦除后的 Class
Class<?> rawClass = t.getType();
// 获取原始 Type
Type originType = t.getOriginType();
// 获取泛型 Type
Type genericType = t.getGenericType();
// 获取泛型变量映射
Map<String, Type> genericInfo = t.getGenericInfo();
// 例如:{K=String, V=UserModel}
4、完整示例
public class TypeMetadataDemo {
private static final Eggg eggg = new Eggg();
public static void main(String[] args) {
// 示例 1:分析 Map 的泛型
TypeEggg t1 = eggg.getTypeEggg(new HashMap<Integer, String>() {}.getClass());
if (t1.isMap() && t1.isParameterizedType()) {
Type keyType = t1.getActualTypeArguments()[0]; // Integer
Type valueType = t1.getActualTypeArguments()[1]; // String
System.out.println("Key: " + keyType + ", Value: " + valueType);
}
// 示例 2:分析 List 的泛型
TypeEggg t2 = eggg.getTypeEggg(new ArrayList<UserModel>() {}.getClass());
System.out.println(t2.isCollection()); // true
System.out.println(t2.isList()); // true
System.out.println(t2.getActualTypeArguments()[0]); // UserModel
// 示例 3:分析普通类
TypeEggg t3 = eggg.getTypeEggg(UserModel.class);
System.out.println(t3.isJdkType()); // false
System.out.println(t3.getType()); // UserModel.class
}
}
5、TypeEggg API 速查
类型判断方法
| 方法 | 返回值 | 说明 |
|---|---|---|
isCollection() | boolean | 是否为 Collection 类型 |
isList() | boolean | 是否为 List 类型 |
isSet() | boolean | 是否为 Set 类型 |
isMap() | boolean | 是否为 Map 类型 |
isArray() | boolean | 是否为数组 |
isEnum() | boolean | 是否为枚举 |
isPrimitive() | boolean | 是否为基本类型 |
isString() | boolean | 是否为 String |
isNumber() | boolean | 是否为数字类型 |
isBoolean() | boolean | 是否为布尔类型 |
isObject() | boolean | 是否为 Object |
isJdkType() | boolean | 是否为 JDK 内置类型 |
isInterface() | boolean | 是否为接口 |
isAbstract() | boolean | 是否为抽象类 |
泛型分析方法
| 方法 | 返回值 | 说明 |
|---|---|---|
isParameterizedType() | boolean | 是否为参数化类型 |
getParameterizedType() | ParameterizedType | 获取参数化类型 |
getActualTypeArguments() | Type[] | 获取实际泛型参数 |
isTypeVariable() | boolean | 是否为类型变量 |
getTypeVariable() | TypeVariable | 获取类型变量 |
isWildcardType() | boolean | 是否为通配符类型 |
getWildcardType() | WildcardType | 获取通配符类型 |
isGenericArrayType() | boolean | 是否为泛型数组类型 |
getGenericArrayType() | GenericArrayType | 获取泛型数组类型 |
类型访问方法
| 方法 | 返回值 | 说明 |
|---|---|---|
getType() | Class<?> | 擦除后的 Class |
getOriginType() | Type | 原始 Type |
getGenericType() | Type | 经过特化的泛型 Type |
getGenericInfo() | Map<String, Type> | 泛型变量映射 |
getClassEggg() | ClassEggg | 获取类元数据 |
6、补充说明
匿名子类的作用
Java 的泛型擦除是语言层面的设计,无法修改。但匿名子类有一个特性:编译器会在其父类签名中保留泛型参数信息。new HashMap<String, Integer>() {} 中的 {} 创建了一个匿名子类,泛型参数 <String, Integer> 会被记录在字节码中,供运行时读取。
Type 和 Class 的区别
Class 是 Type 的一种具体形态。Type 是更上层的概念,除了普通的 Class,还包括参数化类型 ParameterizedType、类型变量 TypeVariable、通配符 WildcardType 等。EggG 通过 TypeEggg 将这些类型统一封装。
缓存机制
TypeEggg 内部使用软引用(SoftReference)做缓存。同一类型多次调用 getTypeEggg() 时,解析只执行一次。内存紧张时缓存会自动释放。