Solon v3.10.7

类型元数据分析

</> markdown
2026年5月29日 上午8:57:27

1、为什么需要类型分析?

在开发框架时,经常需要在运行时获取泛型的真实类型信息。例如:

  • JSON 反序列化时,需要知道 List 字段的元素是 String 还是 UserModel
  • ORM 框架映射查询结果时,需要知道 Map 的 Key 和 Value 分别是什么类型
  • 依赖注入容器在解析泛型依赖时,需要获取完整的泛型参数信息

Java 的泛型在编译后会被擦除,运行时只能看到原始类型。TypeEggg 通过解析匿名子类的父类签名,在运行时还原泛型信息。


TypeEggg 是 EggG 的两大核心能力之一,它对 java.lang.reflect.Type 进行了统一包装,提供类型判断和泛型信息访问能力。

2、TypeEggg 概述

TypeEggg 提供以下能力:

  1. 类型识别 — 判断是普通 Class、参数化类型、还是类型变量
  2. 泛型参数提取 — 获取 Map<K, V>K → StringV → UserModel 等对应关系
  3. 原始类型获取 — 返回擦除后的 Class 对象(默认 Object.class
  4. 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 的区别

ClassType 的一种具体形态。Type 是更上层的概念,除了普通的 Class,还包括参数化类型 ParameterizedType、类型变量 TypeVariable、通配符 WildcardType 等。EggG 通过 TypeEggg 将这些类型统一封装。

缓存机制

TypeEggg 内部使用软引用(SoftReference)做缓存。同一类型多次调用 getTypeEggg() 时,解析只执行一次。内存紧张时缓存会自动释放。