当前位置: 首页 > news >正文

Spring ResolvableType说明

Spring ResolvableType说明

背景

ResolvableType 是 Spring 框架提供的一个封装类,专门用来在运行时解析和处理复杂的泛型类型信息,解决了 Java 反射 API 在泛型处理上的不便。它可以看作是对 java.lang.reflect.Type 系列接口的更高层抽象,尤其是在处理嵌套泛型、通配符、类型变量时优势明显。

java 泛型在编译后会被擦除,常规反射只能拿到原始类型,比如 List<String> 在运行时只是 List。虽然可以通过 ParameterizedType 等接口获取一些泛型信息,但操作繁琐,且缺乏递归解析、类型变量替换等能力。

ResolvableType 能轻松做到:

  • 获取字段、方法参数、返回值上的完整泛型结构
  • 在继承层次中解析某个泛型接口的实际类型参数
  • 处理多层嵌套泛型如 Map<String, List<Integer>>

在Spring的事件机制中被广泛使用。

Java原生使用

对于以下泛型类型,没有子类的帮助下,是无法获取具体的运行时类型的

public class ApplicationListener<T> {void onApplicationListener(T event) {}public static void main(String[] args) {// 没有办法拿到listener对象实际的运行时泛型类型ApplicationListener<String> listener = new ApplicationListener<>();}
}

如果在有子类的情况下,便可以借助Class.getGenericSuperclass或者getGenericInterfaces方法来获取到实际的泛型类型了。

public abstract class ApplicationListener<T> {abstract void onApplicationListener(T event);static class StringApplicationListener extends ApplicationListener<String> {@Overridevoid onApplicationListener(String event) {}}public static void main(String[] args) {ApplicationListener<String> listener = new StringApplicationListener();Type superclass = listener.getClass().getGenericSuperclass();if (superclass instanceof ParameterizedType) {ParameterizedType parameterizedType = (ParameterizedType)superclass;Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();// trueSystem.out.println(actualTypeArguments[0] instanceof Class<?>);// class java.lang.StringSystem.out.println(actualTypeArguments[0]);}}
}

ResolvableType API使用

创建 ResolvableType 实例

表格中只例举了常用几个

方法 说明
forClass(Class<?>) 包装一个原始类
forType(Type) 包装任意 java.lang.reflect.Type
forInstance(Object) 根据实例创建
forClass(Class baseType, Class implementationClass) 基于实现类推导泛型
ResolvableType forClassWithGenerics(Class, Class... ) 包含泛型

使用示例

package com.wangtao.springboottest;import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.core.ResolvableType;public class ResolvableTypeTest {public static class PayloadEvent<T> {}public static class StringPayloadEvent extends PayloadEvent<String> {}@Testpublic void testCreateApi() {ResolvableType type = ResolvableType.forClass(PayloadEvent.class);Assertions.assertEquals("com.wangtao.springboottest.ResolvableTypeTest$PayloadEvent<?>", type.toString());// 指定泛型type = ResolvableType.forClassWithGenerics(PayloadEvent.class, String.class);Assertions.assertEquals("com.wangtao.springboottest.ResolvableTypeTest$PayloadEvent<java.lang.String>", type.toString());// 基于实现类构建泛型type = ResolvableType.forClass(PayloadEvent.class, StringPayloadEvent.class);Assertions.assertEquals("com.wangtao.springboottest.ResolvableTypeTest$PayloadEvent<java.lang.String>", type.toString());// 上面底层就是这个type = ResolvableType.forClass(StringPayloadEvent.class).as(PayloadEvent.class);Assertions.assertEquals("com.wangtao.springboottest.ResolvableTypeTest$PayloadEvent<java.lang.String>", type.toString());StringPayloadEvent event = new StringPayloadEvent();// 类似forClasstype = ResolvableType.forInstance(event);Assertions.assertEquals("com.wangtao.springboottest.ResolvableTypeTest$StringPayloadEvent", type.toString());}
}

核心方法与解析能力

方法 说明
Class<?> resolve() 返回擦除后的原生类型
ResolvableType getGeneric(int... indexes) 递归获取指定位置的泛型参数
ResolvableType[] getGenerics() 获取泛型参数数组
ResolvableType getSuperType() 父类对应的 ResolvableType,已包含子类绑定的实参
ResolvableType[] getInterfaces() 接口数组(同样绑定好实参)
ResolvableType as(Class<?> type) 将当前类型向上转型到指定父类或接口,保留泛型绑定
boolean isAssignableFrom(ResolvableType other) 类型兼容性判断,支持泛型(扩展Class.isAssignableFrom)
boolean isInstance(Object obj) 判断对象是不是当前类型的实例,支持泛型(扩展Class.isInstance)

使用示例

package com.wangtao.springboottest;import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.core.ResolvableType;import java.util.Arrays;
import java.util.List;public class ResolvableTypeTest {public static class PayloadEvent<T> {}public static class StringPayloadEvent extends PayloadEvent<String> {}@Testpublic void testGetApi() {// 指定泛型ResolvableType type = ResolvableType.forClassWithGenerics(PayloadEvent.class, String.class);// 获取原始类型Assertions.assertEquals(PayloadEvent.class, type.resolve());// 获取第一个位置的泛型参数Assertions.assertEquals("java.lang.String", type.getGeneric(0).toString());// 构造一个嵌套的泛型结构(List<PayloadEvent<String>>)type = ResolvableType.forClassWithGenerics(List.class, type);Assertions.assertEquals("java.util.List<com.wangtao.springboottest.ResolvableTypeTest$PayloadEvent<java.lang.String>>", type.toString());// 递归获取,先获取第一个位置的泛型参数, 从这个结果泛型参数中继续获取第一个位置的泛型参数Assertions.assertEquals("java.lang.String", type.getGeneric(0, 0).toString());type = ResolvableType.forClassWithGenerics(PayloadEvent.class, String.class);// 获取泛型参数列表ResolvableType[] genericArr = type.getGenerics();Assertions.assertEquals("[java.lang.String]", Arrays.toString(genericArr));type = ResolvableType.forClass(StringPayloadEvent.class);// 获取父类型(会保留具体的泛型参数)Assertions.assertEquals("com.wangtao.springboottest.ResolvableTypeTest$PayloadEvent<java.lang.String>", type.getSuperType().toString());// 向上转型到父类型(会保留具体的泛型参数)type = type.as(PayloadEvent.class);Assertions.assertEquals("com.wangtao.springboottest.ResolvableTypeTest$PayloadEvent<java.lang.String>", type.toString());}
}
http://www.zskr.cn/news/1513107.html

相关文章:

  • 别再只会用朴素算法了!LCA问题从入门到精通:倍增与Tarjan实战详解(附C++代码)
  • 5分钟快速上手:CheatEngine-DMA插件高效内存修改完整指南
  • 父亲节不同兴趣的爸爸送什么礼物才不闲置?先看这6个判断标准 - GrowthUME
  • MPC5674F:高效发动机控制核心架构、外设与应用实战解析
  • 2026巴州库尔勒学车考驾照全流程攻略:品类选型、合规标准及落地指南 - GrowthUME
  • MATLAB版非均匀傅里叶变换工具集:含NUSFT原创算法与多种加速实现
  • WordPress AI评论助手:人机协同回复实战指南
  • 汽车电子系统基础芯片(SBC)UJA1169A:设计、选型与实战应用
  • 2026实力厂家:洛阳市盛装工贸有限公司——专业异性泡沫盒定制与生产源头企业 - 品牌发掘
  • Noto字体企业级多语言解决方案:900+语言支持与全球化部署架构设计
  • STM32L4 Keil工程:全局变量精准落址到备份SRAM/CCM/外扩RAM的完整实现方案
  • Ozon 新手选品合作厂家|避坑 + 选品 + 供应链全攻略,小白也能稳出单
  • 别再傻傻分不清!KingbaseES里用户、角色、模式到底啥关系?一个登录权限就搞定
  • LLM 能力集成:结构化输出与 JSON Schema 约束的工程实践
  • 一场“最不AI”的发布会,苹果在奉行“保守主义”?
  • SpringBoot+Vue +游戏交易系统平台完整项目源码+SQL脚本+接口文档【Java Web毕设】
  • 想要找到技术过硬的激光打标机解决方案这些筛选角度值得参考 - 资讯快报
  • Unity 2D导航网格革命:NavMeshPlus深度解析与实战应用
  • 2026 年北京团建公司推荐 专业服务商综合测评指南 - GrowthUME
  • 2026海口瓷砖空鼓维修哪家好?地砖墙砖翘起起拱专业修复推荐 - 苏易修缮
  • 想要在深圳找到专业靠谱的GEO团队,哪家口碑实力真的更靠得住? - 资讯快报
  • Noto字体完全指南:为全球900+语言终结“豆腐块“的终极解决方案
  • Prompt to Protocol:将提示词升格为可验证的系统协议
  • 急于求成盼翻身,醒悟人生都是细水长流
  • 四川靠谱爬架网实力厂家怎么选?行业内行选购全攻略,钢丝网/防护网/钢格板/钢筋网片/草原网/爬架网,爬架网企业哪家好 - 品牌推荐师
  • Zybo开发板可用的Verilog同步/异步FIFO完整工程:含仿真测试、波形配置与板级约束
  • 从理论到实践:两阶段单纯形算法求解线性规划问题的编程实现
  • TVA视觉智能体工业落地进阶实战(三十六):TVA物料条码+字符OCR高阶识别|畸变条码、磨损字符、曲面喷码、逆光码读取优化方案
  • PVZ Toolkit终极指南:5分钟掌握植物大战僵尸完整修改器使用技巧
  • 5分钟彻底告别Edge浏览器:EdgeRemover工具完全指南