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

Java 泛型与类型擦除:为什么解析对象时能保留泛型信息?

引言:泛型的“魔术”与类型擦除的困境

在 Java 中,泛型为开发者提供了类型安全的集合操作,但其背后的**类型擦除(Type Erasure)**机制却常常让人困惑。你是否遇到过这样的场景?

List<String> list = new ArrayList<>();
list.add("Hello");
// 运行时无法通过 list.getClass() 获取泛型类型 String

这种运行时泛型信息的丢失,可能导致 JSON 反序列化失败或类型转换错误。但有趣的是,当我们反序列化一个完整的对象时,泛型却能奇迹般地被正确识别。本文将揭开这一现象的底层原理,并通过实际代码示例为你解惑。


一、类型擦除的本质与影响

1.1 什么是类型擦除?

Java 泛型是编译时特性。为了兼容旧版本 JVM,编译器会移除所有泛型信息:

  • List<String> 在编译后会变为原始类型 List
  • 泛型类型参数(如 String)仅在编译阶段进行类型检查。

1.2 运行时为何无法直接获取泛型?

public static void main(String[] args) {List<String> stringList = new ArrayList<>();System.out.println(stringList.getClass()); // 输出:class java.util.ArrayList(无法看到 String 类型)
}

根本原因:泛型信息未被写入字节码,运行时 JVM 只能看到原始类型。


二、解析整个对象时的“魔法”:为什么泛型能保留?

2.1 实际场景分析

假设有以下类定义(来自用户提供的代码):

public class Event {// 关键字段:泛型集合private List<String> questions;
}

当使用 JSON 框架反序列化时:

Event  event = JsonUtil.parseObject(jsonStr, Event .class);

问题:为何 questions字段的泛型类型 String能被正确识别?

2.2 核心原理揭秘

原理 ①:类结构保留了泛型元数据
  • 编译时记录:虽然运行时类型擦除了泛型,但类的字段声明(如 private List<String> questions;)的泛型信息会被记录在 .class 文件的元数据中。
  • 反射可读取:通过 Java 反射 API 的 Field.getGenericType() 方法,可以获取字段的完整泛型类型。
原理 ②:JSON 框架的智能处理
  • 步骤拆解
    1. 解析目标类 Event.class
    2. 扫描字段questions,发现其类型为 List<String>
    3. 通过反射获取泛型参数String的类型信息。
    4. 根据类型信息反序列化 JSON 数组中的每个元素。
关键代码验证
Field field = Event.class.getDeclaredField("questions");
Type genericType = field.getGenericType();// 输出:java.util.List<java.lang.String>
System.out.println(genericType); 

三、单独解析集合的困境与解决方案

3.1 问题场景

如果直接解析一个纯集合 JSON:

[{"content": "题目1"},{"content": "题目2"}
]

尝试反序列化:

List<AbstractTopicDto> list = JsonUtil.parseObject(jsonStr, List.class); // ❌ 失败!

此时,由于类型擦除,List.class 无法提供泛型信息,框架无法知道元素的具体类型。

3.2 解决方案:TypeReference 的妙用

通过匿名内部类保留泛型信息:

List<String> list = JsonUtil.parseObject(jsonStr, new TypeReference<List<String>>() {} // ✅ 匿名类携带泛型信息
);
原理解释
  • 匿名类继承TypeReference<List<String>> 的子类在编译时会保留泛型参数。
  • 框架读取方式:通过 getGenericSuperclass() 方法获取父类的泛型类型。

四、对比总结:何时泛型信息可用?

场景是否保留泛型原因
直接访问 List 变量的泛型❌ 否类型擦除后运行时无信息
解析完整对象(如Event✅ 是类字段的泛型信息保存在元数据中,可通过反射获取
使用 TypeReference✅ 是匿名内部类的泛型参数通过父类类型保留

五、最佳实践与避坑指南

  1. 优先传递完整对象类型
    在反序列化时,尽量传递包含泛型字段的类(如 Event.class),而非直接操作集合。

  2. 避免裸类型(Raw Type)
    不要使用 List.classMap.class,而应通过 TypeReference 指定泛型。

  3. 谨慎使用反射获取泛型
    若需手动处理泛型,确保理解 ParameterizedTypeTypeVariable 的区别。

  4. 单元测试验证泛型行为
    针对泛型字段编写测试,确保序列化/反序列化逻辑正确。


结语:泛型的“可见性”取决于上下文

Java 的类型擦除机制虽然带来了限制,但通过类结构的元数据和框架的智能处理,我们仍然能在关键场景下“找回”泛型信息。理解这一机制,能够帮助开发者更高效地处理 JSON 序列化、反射操作等复杂场景。正如代码中的Event所示,合理设计对象结构,可以让泛型在运行时“隐而不失”,继续发挥其类型安全的威力。

相关文章:

Java 泛型与类型擦除:为什么解析对象时能保留泛型信息?

引言&#xff1a;泛型的“魔术”与类型擦除的困境 在 Java 中&#xff0c;泛型为开发者提供了类型安全的集合操作&#xff0c;但其背后的**类型擦除&#xff08;Type Erasure&#xff09;**机制却常常让人困惑。你是否遇到过这样的场景&#xff1f; List<String> list …...

达梦数据库多版本并发控制(MVCC)_yxy

达梦数据库多版本并发控制 1 多版本并发控制解决了什么问题&#xff1f;2 达梦MVCC实现方式2.1 版本链结构2.1.1 物理记录2.1.2 回滚记录2.1.3 版本链实现方式 2.2 可见性原则2.3 历史数据获取 1 多版本并发控制解决了什么问题&#xff1f; MVCC&#xff08;Multi-Version Con…...

math.js 加/减/乘/除 使用

math.js 加/减/乘/除 使用 安装 npm install mathjs引入 import * as math from "mathjs";使用 // 加法 let addNumber math.add( math.bignumber(0.1), math.bignumber(0.3)) // 加法 保留两位小数 let addNumber1 math.format(math.add( math.bignumber(0.1…...

python的家教课程管理系统

目录 技术栈介绍具体实现截图系统设计研究方法&#xff1a;设计步骤设计流程核心代码部分展示研究方法详细视频演示试验方案论文大纲源码获取/详细视频演示 技术栈介绍 Django-SpringBoot-php-Node.js-flask 本课题的研究方法和研究步骤基本合理&#xff0c;难度适中&#xf…...

计算机组成原理——数据的表示

2.1数据的表示 整理自Beokayy_ 1.进制转换 十六进制与二进制的转换 一位十六进制等于四位二进制 四位二进制等于一位十六进制 0x173A4C0001 0111 0011 1010 0100 1100 十六进制与十进制的转换 十六转十&#xff1a;每一位数字乘以相应的16的幂再相加 十转十六&#xff1a…...

实现书签-第一部分

实现书签-第一部分 本节我们将实现书签功能&#xff0c;为菜谱点击类似于收藏的功能&#xff0c;然后可以在上方的书签找到我们所有收藏的书签&#xff1b; 在此之前&#xff0c;让我们修复一下之前的功能BUG&#xff0c;当我们搜索的时候&#xff0c;下面分页始终保持在上一…...

解决将其他盘可用空间,移植到C盘

第一步首先下载安装 用来扩内存盘的实用工具资源-CSDN文库 第二步打开diskgenius.exe 第三步选中想扩容的盘 右击-》选择扩容分区-》选择要缩小的分区-》然后确定 第四步拖拽对勾的地方 或者在箭头地方输入想阔的大小&#xff0c;然后开始&#xff0c;一直确定&#xff0c;就…...

第二天的尝试

目录 一、每日一言 二、练习题 三、效果展示 四、下次题目 五、总结 一、每日一言 清晰的明白自己想要的是什么&#xff0c;培养兴趣也好&#xff0c;一定要有自己的一技之长。我们不说多优秀&#xff0c;但是如果父母需要我们出力&#xff0c;不要只有眼泪。 二、练习题 对…...

k8s灰度发布

基于 Traefik 的加权灰度发布-腾讯云开发者社区-腾讯云 Traefik | Traefik | v1.7 Releases traefik/traefik GitHub 从上面连接下载后上传到harbor虚拟机 vagrant upload /C/Users/HP280/Downloads/traefik 下载配置文件 wget -c http://raw.githubusercontent.com/conta…...

前端面经 9 JS中的继承

借用Class实现继承 实现继承 extends super extends 继承父类 super调用父类的构造函数 子类中存在方法采取就近原则 &#xff0c;子类构造函数需要使用super()调用父类的构造函数 JS 静态属性和私有属性 寄生组合式继承...

memcached主主复制+keepalive

一、Memcached主主复制技术原理 Memcached原生不支持复制&#xff0c;需通过repcached分支实现双向同步。其关键机制包括&#xff1a; 双向同步架构 两节点互为主备&#xff08;Master-Master&#xff09;&#xff0c;任意节点写入的数据会同步至对端。同步基于TCP协议&#x…...

光学设计核心

光学设计核心技术全流程教学&#xff1a;从理论建模到工程实践 一、光学设计基础理论体系构建 1.1 光线传播核心定律 • 斯涅尔定律&#xff1a;n_1\sin\theta_1 n_2\sin\theta_2&#xff0c;通过编程实现折射角动态计算&#xff08;Python示例&#xff09;&#xff1a; im…...

使用 `aiohttp` 构建高效的异步网络爬虫系统

使用 aiohttp 构建高效的异步网络爬虫系统 引言 在爬取大量网页时,传统同步方法(如 requests)可能面临网络 I/O 阻塞问题,导致性能低下。而 Python 的 aiohttp 结合 asyncio 提供了一种高效的解决方案,使得爬虫可以同时处理多个请求,大幅提升数据抓取速度。 本文将详细…...

Microsoft Azure 服务4月更新告示

由世纪互联运营的 Microsoft Azure 重要更新 名称变更 Azure Stack HCI现已正式更名为Azure Local&#xff0c;并成为其重要组成部分。Azure Local是一种超融合基础设施&#xff08;HCI&#xff09;解决方案&#xff0c;专为托管Windows和Linux虚拟机&#xff08;VM&#xff…...

idea运行

各种小kips Linuxidea上传 Linux 部署流程 1、先在idea打好jar包&#xff0c;clean之后install 2、在Linux目录下&#xff0c;找到对应项目目录&#xff0c;把原来的jar包放在bak文件夹里面 3、杀死上一次jar包的pid ps -ef|grep cliaidata.jar kill pid 4、再进行上传新的jar…...

第八天——贪心算法——队列重构问题

1. 题目 给定一个由人群组成的数组 people&#xff0c;其中每个人以 [hi, ki] 的形式表示&#xff0c;people[i] [hi, ki] 表示第 i 个人的身高为 hi&#xff0c;并且前面恰好有 ki 个身高大于或等于 hi 的人。 你需要重新构造并返回一个表示队列的数组 queue&#xff0c;其中…...

CVPR2025 | 首个多光谱无人机单目标跟踪大规模数据集与统一框架, 数据可直接下载

论文介绍 题目&#xff1a;MUST: The First Dataset and Unified Framework for Multispectral UAV Single Object Tracking 期刊&#xff1a;IEEE/CVF Computer Vision and Pattern Recognition Conference 论文&#xff1a;https://arxiv.org/abs/2503.17699 数据&#x…...

Docker实现MySQL数据库主从复制

一、拉取数据库镜像 docker pull mysql:5.7二、创建两个数据库(一主一从模式) mysql01&#xff08;主&#xff09; 1.docker run -d -p 3310:3306 -v /root/mysql/node-1/init:/docker-entrypoinit-initdb.d -v /root/mysql/node-1/config:/etc/mysql/conf.d -v /root/mysq…...

PTN中的L2VPN与L3VPN技术详解

文章目录 一、PTN网络中的VPN技术概述二、L2VPN&#xff08;二层虚拟专用网络&#xff09;技术解析1. 核心技术原理2. 主要类型3. 应用场景4. 技术优缺点 三、L3VPN&#xff08;三层虚拟专用网络&#xff09;技术解析1. 核心技术原理2. 主要类型3. 应用场景4. 技术优缺点 四、L…...

2025长三角杯数学建模B题教学思路分析:空气源热泵供暖的温度预测

2025长三角杯数学建模B题教学思路模型代码&#xff0c;详细内容见文末名片 一、问题背景 在当今“电供暖”日益普及的大背景下&#xff0c;空气源热泵凭借其独特优势&#xff0c;在楼宇供暖领域崭露头角&#xff0c;成为缓解电网调峰压力的得力助手。然而&#xff0c;供暖过程…...

告别传统的防抖机制,提交按钮的新时代来临

目录 背景 目标 核心代码 样式定义&#xff1a;让图标居中、响应父级颜色 SVG 图标&#xff1a;轻量、无依赖的 loading 图标 指令注册&#xff1a;全局注册 v-bLoading DOM 操作&#xff1a;添加与清除 loading 图标 1. 添加 loading 图标 2. 清除 loading 图标 动画…...

InternVL3: 利用AI处理文本、图像、视频、OCR和数据分析

InternVL3推动了视觉-语言理解、推理和感知的边界。 在其前身InternVL 2.5的基础上,这个新版本引入了工具使用、GUI代理操作、3D视觉和工业图像分析方面的突破性能力。 让我们来分析一下是什么让InternVL3成为游戏规则的改变者 — 以及今天你如何开始尝试使用它。 InternVL…...

关于 Web安全:1. Web 安全基础知识

一、HTTP/HTTPS 协议详解 1. HTTP协议基础 什么是 HTTP&#xff1f; HTTP&#xff08;HyperText Transfer Protocol&#xff09;是互联网中浏览器和服务器之间传输数据的协议&#xff0c;基于请求-响应模式。它是一个无状态协议&#xff0c;意思是每次请求都是独立的&#x…...

西门子 S1500 PLC 通过 Profinet 对 6 台施耐德 ATV304 变频器的控制,用于 6 台升降台的位置控制。

西门子 S1500 PLC 通过 Profinet 对 6 台施耐德 ATV304 变频器的控制&#xff0c;用于 6 台升降台的位置控制。程序主要特点&#xff1a; 模块化设计&#xff1a;采用功能块数组结构&#xff0c;实现对多台设备的统一控制循环控制&#xff1a;使用 FOR 循环遍历每台升降台&…...

重构金融数智化产业版图:中电金信“链主”之道

近日&#xff0c;《商学院》杂志独家专访了中电金信常务副总经理&#xff08;主持经营工作&#xff09;冯明刚&#xff0c;围绕“金融科技”“数字底座”“架构转型”“AI驱动”等议题&#xff0c;展开了一场关于未来架构、技术变革与系统创新的深入对话。 当下&#xff0c;数字…...

高光谱遥感图像处理之数据分类的fcm算法

基于模糊C均值聚类&#xff08;FCM&#xff09;的高光谱遥感图像分类MATLAB实现示例 %% FCM高光谱图像分类示例 clc; clear; close all;%% 数据加载与预处理 % 加载示例数据&#xff08;此处使用公开数据集Indian Pines的简化版&#xff09; load(indian_pines.mat); % 包含变…...

2025年PMP 学习十六 第11章 项目风险管理 (总章)

2025年PMP 学习十六 第11章 项目风险管理 &#xff08;总章&#xff09; 第11章 项目风险管理 序号过程过程组1规划风险管理规划2识别风险规划3实施定性风险分析规划4实施定量风险分析规划5规划风险应对执行6实施风险应对执行7监控风险监控 目标: 提高项目中积极事件的概率和…...

IEEE 列表会议第五届机器人、自动化与智能控制国际会议

会议地点&#xff1a;中国 成都 会议官网&#xff1a;ICRAIC 主办单位&#xff1a;成都理工大学 协办单位&#xff1a;成都大学 早鸟截稿&#xff1a;2025年7月15日 截稿时间&#xff1a;2025年8月20日 出版信息&#xff1a;IEEE出版&EI数据库 会议时间&#xff1a…...

基于 React Hook 封装 Store 的三种方案

基于 React Hook 封装 Store 的三种方案 方案一&#xff1a;基于 useSyncExternalStore 的轻量级 Store&#xff08;推荐&#xff09; import { useSyncExternalStore } from react;type Store<T> {state: T;listeners: Set<() > void>; };function createSt…...

Gmsh 读取自定义轮廓并划分网格:深入解析与实践指南

一、Gmsh 简介 (一)Gmsh 是什么 Gmsh 是一款功能强大的开源有限元网格生成器,广泛应用于工程仿真、数值模拟以及计算机图形学等领域。它为用户提供了从几何建模到网格划分的一整套解决方案,能够有效处理复杂几何形状,生成高质量的二维和三维网格,满足多种数值方法的需求…...