Java中如何获取泛型类型信息
文章目录
- 声明侧泛型
- 使用侧泛型
- 获取泛型类型相关方法
- 1. Class类的泛型方法
- 2. Field类的泛型方法
- 3. Method类的泛型方法
- 4. ParameterizedType类
- 获取声明侧的泛型类型信息
- 获取使用侧的泛型类型信息
- 匿名内部类实现获取使用侧的泛型类型
根据使用泛型位置的不同可以分为:声明侧泛型、使用侧泛型。
声明侧的泛型信息被记录在Class文件的Constant pool中以Signature的形式保存。而使用侧的泛型信息并没有保存。
声明侧泛型
声明侧泛型包括:
- 泛型类,或泛型接口的声明
- 带有泛型参数的成员变量
- 带有泛型参数的方法
使用侧泛型
使用侧泛型包括:
- 方法的局部变量,
- 方法调用时传入的变量
获取泛型类型相关方法
上文有提到,声明侧的泛型被记录在Class文件的Constant pool中以Signature的形式保存。
JDK的Class、Field、Method类提供了一些列的获取泛型类型的相关方法。
1. Class类的泛型方法
-
Type getGenericSuperclass():获取父类的Type
- 若父类有泛型,返回的实际Type是ParameterizedType接口的实现类ParameterizedTypeImpl类
- 若父类无泛型,返回的实际Type是Class类
-
Type[] getGenericInterfaces():获取父接口的Type集合
- 若父类有泛型,返回的实际Type是ParameterizedType接口的实现类ParameterizedTypeImpl类
- 若父类无泛型,返回的实际Type是Class类
2. Field类的泛型方法
-
Type getGenericType():获取字段的Type
- 若字段有泛型,返回的实际Type是ParameterizedType接口的实现类ParameterizedTypeImpl类
- 若字段无泛型,返回的实际Type是Class类
3. Method类的泛型方法
-
Type getGenericReturnType():获取方法返回值的Type
- 若返回值有泛型,返回的实际Type是ParameterizedType接口的实现类ParameterizedTypeImpl类
- 若返回值无泛型,返回的实际Type是Class类
-
Type[] getGenericParameterTypes():获取方法参数的Type集合
- 若方法参数有泛型,返回的实际Type是ParameterizedType接口的实现类ParameterizedTypeImpl类
- 若方法参数无泛型,返回的实际Type是Class类
-
Type[] getGenericExceptionTypes():获取方法声明的异常的Type集合
- 若方法参数有泛型,返回的实际Type是ParameterizedType接口的实现类ParameterizedTypeImpl类
- 若方法参数无泛型,返回的实际Type是Class类
4. ParameterizedType类
ParameterizedType是Type的子接口,表示参数化类型,用于获取泛型的参数类型。
ParameterizedType的主要方法:
-
Type[] getActualTypeArguments():获取实际类型参数的Type集合
-
Type getRawType():获取声明此类型的类或接口的Type
-
Type getOwnerType():如果声明此类型的类或接口为内部类,这返回的是该内部类的外部类的Type(也就是该内部类的拥有者)
获取声明侧的泛型类型信息
- 泛型类,或泛型接口的声明
- 带有泛型参数的成员变量
- 带有泛型参数的方法
示例:
public class MyTest extends TestClass<String> implements TestInterface1<Integer>,TestInterface2<Long> {private List<Integer> list;private Map<Integer, String> map;public List<String> aa() {return null;}public void bb(List<Long> list) {}public static void main(String[] args) throws Exception {System.out.println("======================================= 泛型类声明的泛型类型 =======================================");ParameterizedType parameterizedType = (ParameterizedType)MyTest.class.getGenericSuperclass();System.out.println(parameterizedType.getTypeName() + "--------->" + parameterizedType.getActualTypeArguments()[0].getTypeName());Type[] types = MyTest.class.getGenericInterfaces();for (Type type : types) {ParameterizedType typ = (ParameterizedType)type;System.out.println(typ.getTypeName() + "--------->" + typ.getActualTypeArguments()[0].getTypeName());}System.out.println("======================================= 成员变量中的泛型类型 =======================================");ParameterizedType parameterizedType1 = (ParameterizedType)MyTest.class.getDeclaredField("list").getGenericType();System.out.println(parameterizedType1.getTypeName() + "--------->" + parameterizedType1.getActualTypeArguments()[0].getTypeName());ParameterizedType parameterizedType2 = (ParameterizedType)MyTest.class.getDeclaredField("map").getGenericType();System.out.println(parameterizedType2.getTypeName() + "--------->" + parameterizedType2.getActualTypeArguments()[0].getTypeName()+","+parameterizedType2.getActualTypeArguments()[1].getTypeName());System.out.println("======================================= 方法参数中的泛型类型 =======================================");ParameterizedType parameterizedType3 = (ParameterizedType)MyTest.class.getMethod("aa").getGenericReturnType();System.out.println(parameterizedType3.getTypeName() + "--------->" + parameterizedType3.getActualTypeArguments()[0].getTypeName());System.out.println("======================================= 方法返回值中的泛型类型 =======================================");Type[] types1 = MyTest.class.getMethod("bb", List.class).getGenericParameterTypes();for (Type type : types1) {ParameterizedType typ = (ParameterizedType)type;System.out.println(typ.getTypeName() + "--------->" + typ.getActualTypeArguments()[0].getTypeName());}}
}class TestClass<T> {}interface TestInterface1<T> {}interface TestInterface2<T> {}
输出
======================================= 泛型类声明的泛型类型 =======================================
com.joker.test.generic.TestClass<java.lang.String>--------->java.lang.String
com.joker.test.generic.TestInterface1<java.lang.Integer>--------->java.lang.Integer
com.joker.test.generic.TestInterface2<java.lang.Long>--------->java.lang.Long
======================================= 成员变量中的泛型类型 =======================================
java.util.List<java.lang.Integer>--------->java.lang.Integer
java.util.Map<java.lang.Integer, java.lang.String>--------->java.lang.Integer,java.lang.String
======================================= 方法参数中的泛型类型 =======================================
java.util.List<java.lang.String>--------->java.lang.String
======================================= 方法返回值中的泛型类型 =======================================
java.util.List<java.lang.Long>--------->java.lang.Long
获取使用侧的泛型类型信息
上面讲的相关类的获取泛型类型相关方法都只是针对声明侧的泛型。因为声明侧的泛型被记录在Class文件的Constant pool中以Signature的形式保存。所以Java提供了相关方法能获取到这些信息。
那使用侧的泛型信息怎么获取呢?由于使用侧的泛型信息在编译期的时候就被类型擦除了,所以运行时是没办法获取到这些泛型信息的。
难道就真的没办法了吗,其实还是有的。使用侧需要获取泛型信息的地方主要是:方法调用时传入的泛型变量,通常需要在方法中获取变量的泛型类型。比如在JSON解析(反序列化)的场景,他们是怎么实现的了。
针对获取使用侧的泛型类型信息,主要实现方案是通过匿名内部类。
Gson中的泛型抽象类TypeToken<T>,FastJson中的泛型类TypeReference<T>等就是用的该方案。
匿名内部类实现获取使用侧的泛型类型
上文有讲到,在声明侧的泛型中,针对泛型类或泛型接口的声明的泛型,Class类提供了getGenericSuperclass()、getGenericInterfaces()来获取其子类(实现类)上声明的具体泛型类型信息。
而匿名内部类是什么?其本质就是一个继承/实现了某个类(接口,普通类,抽象类)的子类匿名对象。
匿名内部类实现获取使用侧的泛型类型的原理:
- 定义泛型类,泛型类中有一个Type类型的字段,用于保存泛型类型的Type
- 通过匿名内部类的方式创建该泛型类的子类实例(指定了具体的泛型类型)
在创建子类实例的构造方法中,已经通过子类的Class的getGenericSuperclass()获取到了泛型类型信息并复制给了Type类型的字段中。 - 随后任何地方,只要得到了该子类实例,就可以通过实例得到泛型类型的Type,这就得到了使用侧的泛型类信息。
简单示例:
定义泛型类TestClass2<T>,类中包含字段Type
public abstract class TestClass2<T> {private final Type type;public TestClass2() {Type superClass = getClass().getGenericSuperclass();if (!(superClass instanceof ParameterizedType)) {throw new IllegalArgumentException("无泛型类型信息");}type = ((ParameterizedType) superClass).getActualTypeArguments()[0];}public Type getType() {return type;}
}
测试获取泛型类型
public class Test {public static <T> T get(TestClass2<T> tTestClass2) throws IllegalAccessException, InstantiationException {Type type = tTestClass2.getType();Class clazz = (Class) type;return (T)clazz.newInstance();}public static void main(String[] args) throws InstantiationException, IllegalAccessException {String str = get(new TestClass2<String>() {});Date date = get(new TestClass2<Date>() {});}
}
相关文章:
Java中如何获取泛型类型信息
文章目录声明侧泛型使用侧泛型获取泛型类型相关方法1. Class类的泛型方法2. Field类的泛型方法3. Method类的泛型方法4. ParameterizedType类获取声明侧的泛型类型信息获取使用侧的泛型类型信息匿名内部类实现获取使用侧的泛型类型根据使用泛型位置的不同可以分为:声…...
【云原生】centos7搭建安装k8s集群 v1.25版本详细教程实战
文章目录前言一. 实验环境二. k8s 的介绍三 . k8s的安装3.1 搭建实验环境3.1.1 硬件层面的要求3.1.2 软件层面环境配置3.2 docker的安装3.2.1 搭建docker3.2.2 部署 cri-dockerd3.3 部署k8s3.3.1 配置添加阿里云的yum源3.3.2 安装kubeadm kubelet kubectl3.3.3 k8s-master节点初…...
c语言指针
指针 指针是存放地址的变量,也可以说指针地址。 对于定义p(这里的话,只是定义,说明p是指针),p作为一个指针去指向存放数据的位置,而p意思是取(p指向的内存位置的数据)&…...
5.33 综合案例2.0 -ESP32拍照上传阿里云OSS
综合案例2.0 - ESP32拍照上传阿里云OSS案例说明连线功能实现1.阿里云平台连接2.OSS对象存储服务3.ESP32-CAM开发环境4.代码ESP32-CAM开发板代码HaaS506开发板代码测试数据转图片方法案例说明 使用ESP32拍照,将照片数据上传阿里云OSS(通过4G网络上传)。 …...
java无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。 示例 2: 输入: s “bbbbb” 输出: 1 解释: 因为无重复字符的最长子串是 “…...
测试用例设计工作中的应用
1. 等价类划分 常见的软件测试面试题划分等价类: 等价类是指某个输入域的子集合.在该子集合中,各个输入数据对于揭露程序中的错误都是等效的.并合理地假定:测试某等价类的代表值就等于对这一类其它值的测试.因此,可以把全部输入数据合理划分为假设干等价类,在每一个等价类中取一…...
leetcode 困难 —— 数字 1 的个数(简单逻辑题)
(害,做题是真的慢,这面试给我这题我估计就傻了) 题目: 给定一个整数 n,计算所有小于等于 n 的非负整数中数字 1 出现的个数。 题解: 首先看看整数范围 0 < n < 10^9 不能遍历࿰…...
关于JSON
<!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title></title> </head> <body> <script> /* 1、JSON的英文全称:Java…...
Apifox-接口调用、自动化测试工具
Apifox简介 Apifox 的定位是Postman Swagger Mock JMeter,具有API文档管理、API调试、API Mock、API 自动化测试等功能。可以通过一种工具解决之前使用多种工具的数据同步问题。高效、及时、准确! 安装 Apifox的安装非常方便,直接下载安…...
Vue一个项目兼容每个省份的个性化需求
开发环境及打包指令 后拼上省份区划"serve:henan": "yarn && vue-cli-service serve -o --encryptSM2 --zone41","serve:hunan": "yarn && vue-cli-service serve -o --encryptSM2 --zone43","serve:guizhou&quo…...
npm install报错 npm ERR! 的解决办法
以下是四种常见的npm ERR及解决方式错误一、npm ERR! A complete log of this run can be found in:npm ERR!C:\Users\nanyi\AppData\Roaming\npm-cache_logs\2021-09-17T08_58_23_413Z-debug.l查看错误日志,错误日志就在上面展示的C:\Users…这里如果发现错误日志里…...
echarts修改饼图,环形图的圆环宽度,大小
echarts修改环形图的圆环宽度,大小 环形图圆环的大小需要通过series-pie. radius属性来修改 radius 饼图的半径。 Array.<number|string>:数组的第一项是内半径,第二项是外半径。每一项遵从上述 number string 的描述。 把数组的第…...
小白系列Vite-Vue3-TypeScript:010-封装svg
上一篇我们介绍了ViteVue3TypeScript项目中mockjs的安装和配置i。本篇我们来介绍封装SVG图标组件。svg特征Preloading所有图标都是在项目运行时生成的,只需要操作一次dom即可。高性能内置缓存,仅在文件被修改时才会重新生成。安装插件vite-plugin-svg-ic…...
卷严重、难度高、激励少,如何适应空投市场新变化
自从空投交互从2020年开始之后,不少人都开始加入到空投交互的行列中,一些项目也因为“格局”的因素,在项目正式上线前都会给早期参与者空投代币,以此吸引大家的关注。但是在越来越多的人加入到撸空投行列之中后,现在整…...
基于Java与JSP的文件上传和下载
概念 当用户在前端页面点击文件上传后,用户上传的文件数据提交给服务器端,实现保存。 文件上传步骤 提交方式: 提供form表单,method必须是post。因为post请求无数据限制。 <form method"post"></form>…...
Gromacs中的g_mmpbsa计算带电底物与蛋白的结合能不准确
g_mmpbsa计算带电底物与蛋白的结合能总是不准确 TOC 在做的两个项目中,利用g_mmpbsa计算带电底物与蛋白的结合能结果非常不可靠,底物带两个硫酸根离子,g_mmpbsa在计算带电的底物与酶的结合能时总是不准确,因此后续若底物带电&…...
【mmrotate】旋转目标检测之训练DOTA数据集
every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 mmrotate训练DOTA数据集记录 1. 正文 1.1 数据准备 数据介绍部分,参考DOTA数据介绍,官方提供了裁剪工具development kit。这里…...
图基本概念
图:顶点和边的集合。无向图:每条边都是无方向的有向图:每条边都是有方向的完全图:任意两个点都有一条边相连稀疏图:有很少边或弧的图稠密图:有较多边或弧的图网:边/弧带权的图邻接:有…...
机器学习基础
一、基本概念 1 学习的概念 1975年图灵奖获得者、1978年诺贝尔经济学奖获得者、著名学者赫伯特.西蒙 (Herbert Simon) 曾下过一个定义: 如果一个系统,能够通过执行某个过程,就此改进了它的性能,那么这个过程就是学习.由此可看出,…...
FreeRTOS-Tickless低功耗模式 | FreeRTOS十四
目录 说明: 一、低功耗模式简介 1.1、STM32低功耗模式 二、Tickless模式 2.1、Tickless模式如何功耗 2.2、Tickless模式设计思想 2.3、为了降低功耗,又不影响系统运行,怎么能做到呢? 三、Tickless模式修改配置 3.1、配置…...
实现了统一消息中心的微服务基础框架 JVS,快点赞收藏
一、开源项目简介基于JVS(基于spring cloud封装)的基础开源框架,实现了基于多对多租户能力的管理系统。二、基础框架实现功能支持数据管理支持分布式定时任务支持分布式日志采集支持系统监控支持动态配置中心支持模板消息支持链路跟踪支持邮件…...
VMware 安装 OpenWrt 旁路由并配置 PassWall
1、准备 OpenWrt 镜像包 我已经转好了 vmdk 格式的,更多的可以去恩山论坛下载 OpenWrtvmdk格式-虚拟化文档类资源-CSDN下载 也可以在这个平台在线定制 OpenWrt固件下载与在线定制编译 2、网络选择 NAT 模式 3、创建虚拟机,选择自定义方式 4、一直下…...
R语言GD包地理探测器分析时报错、得不到结果等情况的解决方案
本文介绍在利用R语言的GD包,实现自变量最优离散化方法选取与执行、地理探测器(Geodetector)操作时,出现各类报错信息、长时间得不到结果等情况的解决方案。 在之前的文章R语言GD包基于栅格图像实现地理探测器与连续参数的自动离散…...
嵌入式开发:你需要知道的5种简单
传达嵌入式软件体系结构设计意图通常伴随着基于嵌入式开发人员经验的假设。你可以从资源受限的基于微控制器的系统的角度来看架构设计。如何设计架构将取决于系统的嵌入式软件分类。有许多不同的方法可以对嵌入式软件进行分类。我发现有五种简单的嵌入式软件分类可以帮助我调整…...
MVC与MVVM
MVC与MVVM举例说明MVCMVVM两者比较MVC <!DOCTYPE html> <html><head><meta charset"utf-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><title>mvc案例</title><link rel"styleshe…...
Cortex-M0异常和中断
目录1.概念2.异常类型3.异常优先级定义4.向量表5.异常流程概述接受异常请求压栈和出栈异常返回指令末尾连锁延迟到达6.EXC_RETURN7.异常入口流程的细节压栈取出向量并更新PC寄存器更新8.异常退出流程的细节1.概念 异常是能够引起程序流偏离正常流程的事件,当异常发…...
数据库(6)--存储过程
一、学习目标 熟悉存储过程的定义和使用,熟练运用 select ,update ,insert ,delete 命令完成对学生信息数据库的查询、更新、添加、删除操作。 二、学习内容 学生(学号,年龄,性别,系名) 课程(…...
c++ 指针、引用和常量
指针、引用和常量的关系_夜悊的博客-CSDN博客 1. ① 指针是对象,引用不是对象(在此可以理解为变量,一个变量是一个对象) 指针不必须初始化引用只是为一个已经存在的对象所起的另一个名字(别名)ÿ…...
1、HAL库UART 中断|DMA 自动回显接收数据
1、实现代码: stm32f4xx_hal_conf.h文件开启UART宏定义 #define HAL_UART_MODULE_ENABLED添加stm32f4xx_hal_uart.c和stm32f4xx_hal_dma.c到自己工程; 编写好的代码:usart_Driver.c /***************************************************…...
NPOI - ConditionalFormattingRule
NPOI 给xls(xlsx)创建条件格式 获取 XSSFSheetConditionalFormatting 对象 初始化 IWorkbook _workbook new XSSFWorkbook(); ISheet _dataSheet _workbook.GetSheet("template"); ISheetConditionalFormatting fcs _dataSheet.SheetConditionalFormatting;调用…...
洛阳做网站的公司/sem竞价托管公司
0x01、基于mysql实现分布式锁基于分布式锁的实现,首先肯定是想单独分离出一台mysql数据库,所有服务要想操作文件(共享资源),那么必须先在mysql数据库中插入一个标志,插入标志的服务就持有了锁,并对文件进行操作&#x…...
个人可以做商城网站/新网站排名优化怎么做
可以在游戏中添加或者删除物品及方块,包括mod附加的东西。保存和读取某个时间点背包机身上的东西。创建一个可以无限使用的物品和工具。可以用来检测mod的功能,创建巨大的用来生存的世界。控制界面开关:在背包界面按“o”可以控制TMI界面的开…...
廊坊网站建设精灵/外贸网站推广的方法
swal()方法是一个提示框;swal({title: "",text: "请扫描用户手机上的付款码",type: "input",showCancelButton: true,closeOnConfirm: false,cancelButtonText: "取消",confirmButtonText: "确认",imageUrl: &qu…...
可信赖的深圳网站建设/2021小学生新闻摘抄
/*** 选择排序的思想:* 每次从待排序列中找到最小的元素,* 然后将其放到待排的序列的最左边,直到所有元素有序** 选择排序改进了冒泡排序,将交换次数从O(N^2)减少到O(N)* 不过比较次数还是O(N)*/package al;public class SelectSo…...
策划公司网站建设/抖音搜索引擎优化
背景:导出excel表,需要导出特定列,EXCEL注解有一个属性isColumnHidden,当为true时候,该列就不会导出 怎么动态修改? // 通过反射 获取目标实体类的目标字段 Field file ForceTaskExpVo.class.getDeclared…...
建立网站怎么赚钱/营销网站定制公司
pwdpwd targetbasename ${pwd}...