获取泛型,泛型擦除,TypeReference 原理分析
说明
- @author blog.jellyfishmix.com / JellyfishMIX - github
- LICENSE GPL-2.0
获取泛型,泛型擦除
- 下图中示例代码是一个工具类用于生成 csv 文件,需要拿到数据的类型,使用反射感知数据类型的字段,来填充表字段名。
- 可以看到泛型 T 没有类似 getClass() 的方法,因为编译后泛型 T 会被擦除,在字节码中不存在 T 这个类型,所以没办法通过 T 来获取某些信息。方法签名中的
java.util.List<T>编译后会变成java.util.List。 - 解决方式是显式传入
Class<?> clazz来指定数据类型。


泛型嵌套
Class<?> clazz只能传递一层数据类型,无法解决泛型嵌套时的数据类型传递问题。- 对于泛型嵌套,例如
List<List<Map<String, Person>>>,这样的类型。如果使用Class<?> clazz来传递,只能感知到最外层的List.class,内层泛型还是会出现泛型擦除的情况。 - 完整地传递泛型嵌套,还是需要感知到具体的泛型。
TypeReference 原理分析–感知具体泛型
- 出现泛型嵌套情况时,获取完整的泛型,也是序列化组件需要面对的问题。解决方法例如 jackson 提供的 TypeReference。
泛型没有完全擦除
- javac 编译后没有把所有持有泛型的位置都做擦除。
- 编译后的字节码中,子类的类签名显式指定了传递给父类的泛型。
根据子类获取向父类传递的泛型理论基础
作为 TypeReference 的替代品,定义一个 CustomTypeHandler,通过演义来展示 TypeReference 的原理,
public abstract class CustomTypeHandler<T extends Object> {
}
再定义一个 ChildCustomTypeHandler 子类,继承父类时声明泛型。
public class ChildCustomTypeHandler extends CustomTypeHandler<List<List<Map<String, Person>>>> {private String tag;
}
编译项目后,使用 jclasslib(一个 IDEA 查看字节码的插件) 查看 ChildCustomTypeHandler.class 字节码,发现 Attributes -> Signature 属性中,记录了类签名,类签名显式指定了传递给父类的泛型。

class 文件结构
jvm 定义了 u1, u2, u4 三种数据结构来表示 1, 2, 4 字节无符号整数。class 文件采用类似 C 语言的结构体来存储数据,如下所示:
ClassFile {u4 magic;u2 minor_version;u2 major_version;u2 constant_pool_count;cp_info constant_pool[constant_pool_count-1];u2 access_flags;u2 this_class;u2 super_class;u2 interfaces_count;u2 interfaces[interfaces_count];u2 fields_count;field_info fields[fields_count];u2 methods_count;method_info methods[methods_count];u2 attributes_count;attribute_info attributes[attributes_count];
}
中文说明:
魔数(Magic Number)
版本号(Minor&Major Version)
常量池(Constant Pool)
类访问标记(Access Flags)
类索引(This Class)
超类索引(Super Class)
接口表索引(Interfaces)
字段表(Fields)
方法表(Methods)
属性表(Attributes)
类的字节码 Attributes -> Signature 属性中,记录了类签名,类签名会显式指定传递给父类的泛型。这是根据子类获取向父类传递的泛型的理论基础,及 TypeReference 的理论基础。
根据子类获取向父类传递的泛型 demo
- getActualTypeArguments 可能会存在多个泛型,例如 Map<K,V> 所以会返回 Type[] 数组。
- 根据 CustomTypeHandler 的约定,只能向 CustomTypeHandler 传递一个最外层 T,因此这里直接通过[0]拿 T。
- 这里拿到的 T 是包含泛型嵌套的。例如子类声明 extends CustomTypeHandler<List<List<Map<String, Person>>>>,这里会拿到 List<List<Map<String, Person>>>
- 如果想继续拿嵌套的内层泛型,可以继续调用 ParameterizedType#getActualTypeArguments
public abstract class CustomTypeHandler<T extends Object> {protected final Type _type;/*** 此方法实际由子类调用*/protected CustomTypeHandler() {Type superClass = getClass().getGenericSuperclass();// sanity check, should never happenif (superClass instanceof Class<?>) {throw new IllegalArgumentException("Internal error: TypeReference constructed without actual type information");}/** getActualTypeArguments 可能会存在多个泛型,例如 Map<K,V> 所以会返回 Type[] 数组* 根据 CustomTypeHandler 的约定,只能向 CustomTypeHandler 传递一个最外层 T,因此这里直接通过[0]拿 T。* 这里拿到的 T 是包含泛型嵌套的。例如子类声明 extends CustomTypeHandler<List<List<Map<String, Person>>>>,这里会拿到 List<List<Map<String, Person>>>* 如果想继续拿嵌套的内层泛型,可以继续调用 ParameterizedType#getActualTypeArguments*/_type = ((ParameterizedType) superClass).getActualTypeArguments()[0];}public Type getType() {return this._type;}
}
扩展阅读
- java Type 接口 https://blog.csdn.net/lvxiangan/article/details/94836504

相关文章:
获取泛型,泛型擦除,TypeReference 原理分析
说明 author blog.jellyfishmix.com / JellyfishMIX - githubLICENSE GPL-2.0 获取泛型,泛型擦除 下图中示例代码是一个工具类用于生成 csv 文件,需要拿到数据的类型,使用反射感知数据类型的字段,来填充表字段名。可以看到泛型…...
springboot 3.x 之 集成rabbitmq实现动态发送消息给不同的队列
背景 实际项目中遇到针对不同类型的消息,发送消息到不同的队列,而且队列可能还不存在,需要动态创建,于是写了如下代码,实践发现没啥问题,这里分享下。 环境 springboot 3.2 JDK 17 rabbitMQ模型介绍 图片…...
C++ 代码实现鼠标右键注册菜单,一级目录和二级目录方法
最近做的一个项目, 在使用windows的时候,我希望在右键菜单中添加一个自定义的选项, 该选项下有我经常使用的多个程序快捷方式, 直接上代码 头文件 #pragma once #include <Windows.h> #include <iostream> #include <string> using namespace std; …...
SQLite 3 优化批量数据存储操作---事务transaction机制
0、事务操作 事务的目的是为了保证数据的一致性和完整性。 事务(Transaction)具有以下四个标准属性,通常根据首字母缩写为 ACID: 原子性(Atomicity):确保工作单位内的所有操作都成功完成&…...
[程序员] 表达的能力
之前看CSDN的问答区,很多时候,感觉问题的描述所要表达的意思非常模糊,或者说描述不清。如果是想回答问题的人想回答问题,首先要搞清楚是什么问题,就需要再问问题主很多细节的东西。三来四去,才能搞清楚具体…...
rknn转换后精度差异很大,失真算子自纠
下面是添加了详细注释的优化代码: import cv2 import numpy as np import onnx import onnxruntime as rt from onnx import helper, shape_inferencedef get_all_node_names(model):"""获取模型中所有节点的名称。参数:model (onnx.ModelProto): O…...
【C语言】解决C语言报错:Stack Overflow
文章目录 简介什么是Stack OverflowStack Overflow的常见原因如何检测和调试Stack Overflow解决Stack Overflow的最佳实践详细实例解析示例1:递归调用过深示例2:分配过大的局部变量示例3:嵌套函数调用过多 进一步阅读和参考资料总结 简介 St…...
【滚动哈希 二分查找】1044. 最长重复子串
本文涉及知识点 滚动哈希 二分查找算法合集 LeetCode 1044. 最长重复子串 给你一个字符串 s ,考虑其所有 重复子串 :即 s 的(连续)子串,在 s 中出现 2 次或更多次。这些出现之间可能存在重叠。 返回 任意一个 可能具…...
webid、sec_poison_id、a1、web_session参数分析与算法实现
文章目录 1. 写在前面2. 参数分析3. 核心算法【🏠作者主页】:吴秋霖 【💼作者介绍】:擅长爬虫与JS加密逆向分析!Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于Python与爬虫领域研究与开发工作! 【🌟作者推荐】:对爬…...
Qt|QWebSocket与Web进行通讯,实时接收语音流
实现功能主要思路:在网页端进行语音输入,PC机可以实时接收并播放语音流。 此时,Qt程序做客户端,Web端做服务器,使用QWebSocket进行通讯,实时播放接收的语音流。 功能实现 想要实现该功能,需要…...
「51媒体」电视台媒体邀约采访报道怎么做?
传媒如春雨,润物细无声,大家好,我是51媒体网胡老师。 电视台作为地方主流媒体,对于新闻报道有着严格的选题标准和报道流程。如果您希望电视台对某个会议或活动进行报道,可以按这样的方法来做: 1.明确活动信…...
Python提取PDF文本和图片,以及提前PDF页面中指定矩形区域的文本
前言 从PDF中提取内容能帮助我们获取文件中的信息,以便进行进一步的分析和处理。此外,在遇到类似项目时,提取出来的文本或图片也能再次利用。要在Python中通过代码提取PDF文件中的文本和图片,可以使用 Spire.PDF for Python 这个…...
C#实现边缘锐化(图像处理)
在 C# 中进行图像的边缘锐化,可以通过卷积滤波器实现。边缘锐化的基本思想是通过卷积核(也称为滤波器或掩模)来增强图像中的边缘。我们可以使用一个简单的锐化核,例如: [ 0, -1, 0][-1, 5, -1][ 0, -1, 0]这个卷积核…...
ffmpeg windows系统详细教程
视频做预览时黑屏,但有声音问题解决方案。 需要将 .mp4编成H.264格式的.mp4 一般上传视频的站点,如YouTube、Vimeo 等,通常会在用户上传视频时自动对视频进行转码,以确保视频能够在各种设备和网络条件下流畅播放。这些网站通常…...
【单片机】MSP430G2553单片机 Could not find MSP-FET430UIF on specified COM port 解决方案
文章目录 MSP430G2553开发板基础知识解决办法如何实施解决办法4步骤一步骤二步骤三 MSP430G2553开发板基础知识 MSP430G2553开发板如下图,上半部分就是UIF程序下载调试区域的硬件。个人觉得MSP430G2553开发板的这个部分没有做好硬件设计,导致很多系统兼…...
每日一题——力扣104. 二叉树的最大深度(举一反三+思想解读+逐步优化)四千字好文
一个认为一切根源都是“自己不够强”的INTJ 个人主页:用哲学编程-CSDN博客专栏:每日一题——举一反三Python编程学习Python内置函数 目录 我的写法 代码功能 代码结构 时间复杂度分析 空间复杂度分析 总结 我要更强 优化方法:迭代&…...
wpf textbox 有焦点 导致后台更新 前台不跟着改变
这个问题可能是由于 WPF 的数据绑定机制导致的。当 TextBox 有焦点时,它会独立于数据绑定进行更新,这可能会导致前台界面不能及时反映后台数据的变化。 1.使用 UpdateSourceTrigger 属性: 在数据绑定时,将 UpdateSourceTrigger 属性设置为 PropertyChanged。这样当 TextBox 的…...
数字化物资管理系统的未来:RFID技术的创新应用
在信息化和智能化不断发展的背景下,物资管理系统的数字化转型已成为各行各业关注的焦点。RFID技术作为一种先进的物联网技术,通过全面数字化实现物资信息的实时追踪和高效管理,为企业的物资管理提供了强有力的支持。 首先,RFID技…...
【docker】常用指令-表格整理
以下列出的指令是Docker中常用的命令,但并不是全部。Docker的指令非常丰富,可以根据具体的需求和场景选择合适的指令。同时,每个指令都有很多选项和参数可以使用,可以通过 docker COMMAND --help 来获取更详细的信息。 一、容器命…...
洛谷——P2824 排序
题目来源:[HEOI2016/TJOI2016] 排序 - 洛谷https://www.luogu.com.cn/problem/P2824 问题思路 本文介绍一种二分答案的做法,时间复杂度为:(nm)*log(n)*log(n).本题存在nlog(n)的做法,然而其做法没有二分答案的做法通俗易懂. 默认读…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...
【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...
Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...
Python Einops库:深度学习中的张量操作革命
Einops(爱因斯坦操作库)就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库,用类似自然语言的表达式替代了晦涩的API调用,彻底改变了深度学习工程…...
