泛型运行时类型参数虽被擦除,但类结构、字段名、方法签名及注解等元数据仍保留在字节码中;orm 利用反射获取的泛型声明(如 parameterizedtype)、泛型类独立 class 对象、泛型边界约束及工厂注入 class 实现高效映射与类型安全。

类型擦除后,泛型的**运行时类型参数确实丢失了**,但关键元数据——比如类结构、字段名、方法签名、注解信息——依然完整保留在字节码中。自研对象数据库的极速 ORM 映射,恰恰不依赖“运行时泛型类型”,而依赖这些**可反射获取的静态结构信息**和**编译期已确定的映射契约**。
用注解+反射提取泛型字段的真实类型
虽然 List<user></user> 运行时变成 List,但字段声明本身(含泛型)在 Field.getGenericType() 中仍可获取 ParameterizedType。这是 Java 反射为数不多保留泛型结构的地方。
- 在实体类字段上标注
@Column或@Relation - 通过
field.getGenericType()判断是否为ParameterizedType,进而解析出实际元素类型(如User) - 对
Map<string order></string>同样可提取键值类型,用于生成嵌套序列化/反序列化逻辑
用泛型类的原始类型做缓存键,避免重复解析
泛型擦除后,Dao<user></user> 和 Dao<order></order> 编译后都是 Dao 类型,但它们的 Class> 对象不同(JVM 为每个泛型实例生成独立的 Class)。这个特性可直接用于高速映射缓存:
- 以
dao.getClass()作为缓存 key,预编译 SQL 模板、字段映射表、JSON 序列化器 - 无需每次执行都解析注解或反射字段,首次加载后全走内存查表
- 比基于字符串拼接(如
"Dao<user>"</user>)更安全、更快、无反射开销
用泛型边界约束替代运行时类型检查
不试图在运行时“恢复” T,而是让泛型边界成为设计契约:
- 定义
interface Entity<id extends serializable></id>,所有实体必须实现它 - ORM 层只依赖
ID的序列化能力,不关心它是Long还是UUID - 主键生成、条件拼接、索引构建全部基于接口行为,而非具体类型
跳过泛型实例化,用工厂方法注入类型上下文
面对 new T[0] 不合法的问题,不硬编码泛型数组,改用工厂:
- 在 DAO 初始化时传入
Class<t></t>,如new UserDao(User.class) - 内部用
Array.newInstance(clazz, size)创建数组 - 配合
clazz.getDeclaredFields()提前构建字段偏移表,后续读写直接按内存布局操作










