泛型擦除到底是怎么一回事

一.泛型擦除

泛型擦除是什么?

众所周知,Java的泛型只在编译时有效,到了运行时这个泛型类型就会被擦除掉,即List<String>List<Integer>在运行时其实都是List<Object>类型。

为什么选择这种实现机制?不擦除不行么? 在Java诞生10年后,才想实现类似于C++模板的概念,即泛型。Java的类库是Java生态中非常宝贵的财富,必须保证向后兼容(即现有的代码和类文件依旧合法)和迁移兼容(泛化的代码和非泛化的代码可互相调用)基于上面这两个背景和考虑,Java设计者采取了"类型擦除"这种折中的实现方式。

同时正正有这个这么"坑"的机制,令到我们无法在运行期间随心所欲的获取到泛型参数的具体类型。

泛型在什么时候擦除?是怎么擦除的?

编译的时候会进行泛型擦除,如果不加限制的话被擦除后在JVM里面变成Object,如果使用extends规定了泛型上界的话,就是以这个上界的类型存储在JVM中。

/**
*编译前的类
*/
public class MainTest2<T extends Number> {private T field;public T function(T value) {return value;}}/**
*编译后字节码后,反编译出的结果
*/
public class MainTest2 {private Number field;public Number function(Number value) {return value;}
}

什么情况下不进行泛型擦除?

父类泛型、成员变量、方法入参和返回值使用到的泛型信息都会保留,并能在运行阶段获取。

//里面所有的泛型都不会被擦除
public class Clazz extends ArrayList<String> {public Map<String, Integer> field;public Set<String> function(List<Number> list) {return null;}}

众所周知,java是在Java5的时候引入的泛型,为了支持泛型,JVM的class文件也做了相应的修改,其中最重要的就是新增了Signature属性表,java编译为字节码后,其申明的泛型信息都存储在Signature中,通过反射获取的泛型信息都来源于这里。

而Signature属性表可以被class文件,字段表,方法表携带,这就使得:类声明,字段声明,方法声明中的泛型信息得以保留。

泛型擦除的仅仅是Code属性表里面的内容,而方法体在字节码中正是存放在Code属性表的。

所谓的java泛型擦除可以理解为只是擦除了方法体的泛型信息。

二.Gson的的TypeToken原理

我们都知道Gson序列化和反序列化是怎么实现的,比如说服务器返回的json数据格式是下面这样的:

{"code":200,"message":"success","data":"{...}"
}

其中data对应的结构不定, 一种考虑是使用泛型:

public class Response<T>{public T data;//简化数据, 省略了其他字段
}

我们把服务器返回的数据转化为Response,反序列化会通过以下代码实现:

String json = "{\"data\":\"data from server\"}";
Type type = new TypeToken<Response<String>>(){}.getType();
Response<String> result = new Gson().fromJson(json, type);

我们为什么需要使用TypeToken来反序列化呢?

这是因为如果我们直接传递Response<String>过去,因为存在泛型擦除,编译过后在JVM里面拿到的是Response<Object>。

这个TypeToken是什么东西呢?

  protected TypeToken() {this.type = getSuperclassTypeParameter(getClass());this.rawType = (Class<? super T>) $Gson$Types.getRawType(type);this.hashCode = type.hashCode();}static Type getSuperclassTypeParameter(Class<?> subclass) {Type superclass = subclass.getGenericSuperclass();if (superclass instanceof Class) {throw new RuntimeException("Missing type parameter.");}ParameterizedType parameterized = (ParameterizedType) superclass;return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);}

可以看到TypeToken的构造函数加了protected修饰,为什么需要加protected呢?

当将构造函数标记为protected,意味着该构造函数只能被同包内或者子类访问到。TypeToken所在的包名是package com.google.gson.reflect,肯定和我们项目不是一个包名。所以这里使用protected的真正意图是让我们创建TypeToken的子类。

我们知道存在Signature属性表里面的泛型不会被擦除调用,Signature属性表又被Class文件携带。

如果我们直接new TypeToken<Response<String>>().getType()的话,还是会被泛型擦除啊!如果是定义一个内部类,内部类上的泛型是不会被擦除的,我们就能正常反序列化了。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/598497.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

windows 10 安装wsl ubuntu

1.首先管理员模式打卡powershell&#xff0c;执行 dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart 2.执行 wsl --update wsl --…

python 基础语法函数

函数定义 def 函数名(形参列表用逗号隔开)&#xff1a; 函数体 return 返回值 # 有参数 无返回值 def my_length(data):count 0for i in data:count 1print(f"data count{count}")my_length(str1) my_length(str2)#无参数无返回值 def say_hello():print("h…

全网唯一值得推荐的C/C++框架和库

全网唯一值得推荐的C/C框架和库 C程序员开发指南 ​ 关注我&#xff0c;天天分享C/C开发技术干货&#xff01; ​关注他 30 人赞同了该文章 ​ 目录 收起 标准库 C通用框架和库 人工智能 异步事件循环 音频 生态学 压缩 并发性 容器 数据库 调试 游戏引擎 图…

Vue中的双向数据绑定是如何实现的

解析 双向数据绑定是Vue框架的核心特性之一&#xff0c;它允许开发者在Vue组件中实现数据的自动同步。当数据发生变化时&#xff0c;视图会自动更新&#xff1b;反过来&#xff0c;当用户在视图中修改数据时&#xff0c;数据也会自动更新。 Vue中的双向数据绑定是通过使用v-m…

死机重启不开机

1. 修改rc文件,使得开机即打开AEE: /vendor/mediatek/proprietary/external/aee/config_external/init.aee.customer.vendor.rc里添加 on init setprop ro.vendor.aee.enforcing no(注意修改此属性后, 无法通过CTS 安全测试项, 在正式发布版本时, 需要恢复默认设置,把此行修…

代码随想录训练营第五十七天| ● 647. 回文子串 ● 516.最长回文子序列● 动态规划总结篇

647. 回文子串 动态规划解决的经典题目&#xff0c;如果没接触过的话&#xff0c;别硬想 直接看题解。 代码随想录 dp数组定义&#xff1a;布尔类型的dp[i][j]&#xff1a;表示区间范围[i,j] &#xff08;注意是左闭右闭&#xff09;的子串是否是回文子串&#xff0c;如果是…

西门子消防主机控制面板显示盘维修B3Q565

作为图形监控主机&#xff0c;负责接收并储存各消防设备主要运行状态&#xff0c;接收火灾报警并显示报警部位&#xff0c;包括火灾报警、状态监视、设备故障报警、网络故障报警﹐指挥抢险救援的活动,进行火灾信息的处理与传送&#xff0c;同时具备提示操作人员的功能&#xff…

TS:类型断言

类型断言好比其他语言中的类型转换&#xff0c;但是不是真正的类型转换方式&#xff0c;之所以不被称为类型转换&#xff0c;是因为转换通常意味着某种运行时的支持。但是&#xff0c;类型断言纯粹是一个编译时语法&#xff0c;同时&#xff0c;它也是一种为编译器提供关于如何…

使用代理IP实现爬虫的匿名性

目录 前言 一、什么是代理IP&#xff1f; 二、使用Python实现代理IP爬虫 1. 安装所需模块 2. 获取代理IP列表 3. 使用代理IP进行爬取 4. 使用代理IP进行数据抓取 三、总结 前言 随着互联网的快速发展&#xff0c;网络爬虫已经成为了获取互联网数据的一种重要方式。然而…

原生JS实现抽奖

1、效果展示 0. 制作一个MiniSize使用提供的素材实现一个转盘活动的布局&#xff08;如下图所示&#xff09;&#xff1b; 进入界面后2秒钟后开始旋转&#xff0c;5秒钟后停止旋转&#xff1b;并且3秒后进入一个表单界面&#xff08;如下图2所示&#xff09;&#xff1b;界面…

vins 实机测试 rs_d435 + imu

vins 实机测试 文章目录 1. imu标定2. camera内参标定3. imu-cam 外参标定4. vins 实际运行5. realsense 1. imu标定 git clone https://github.com/gaowenliang/code_utils.git git clone https://github.com/gaowenliang/imu_utils.git编译运行&#xff0c; roslaunch imu_…

Unity 圆角 线段 绘制 LineRender

需求 绘制圆角 核心函数 /// <summary>/// 点ABC 形成的角度必须为90 点c为中间的点/// </summary>/// <param name"a"></param>/// <param name"b"></param>/// <param name"c"></param>/// &…

CH08_管理状态

Observer 模式 观察者模式&#xff08;Observer&#xff09;&#xff0c;又叫发布订阅模式&#xff08;Publish/Sunscribe&#xff09;模式&#xff0c;定义了一种一对多的依赖关系&#xff0c;让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时&#xf…

2个nodejs进程利用redis 实现订阅发布

1.新建文件 redis_db.js use strict;const redis require(redis); const options {host: "127.0.0.1",port: 6379,password: "123456", // CONFIG SET requirepass "123456" }var array [] for(var i0; i<3; i){const client redis.crea…

git 使用场景 cherry-pick 其他代码仓库代码

Cherry-pick 其他代码库代码 1. git remote add target gitgithub.xxxxxx/testGit.git 1. 添加了一个远程仓库target 2. git fetch target 2. 远程代码抓取到本地 3. git log target/master 3. …

MySQL数据库的CURD、常见函数及UNION和UNION ALL

一、概述 MySQL是一种流行的关系型数据库管理系统&#xff0c;广泛应用于各种应用场景。在MySQL中&#xff0c;CURD操作是指创建&#xff08;Create&#xff09;、读取&#xff08;Read&#xff09;、更新&#xff08;Update&#xff09;和删除&#xff08;Delete&#xff09;…

安装extiverse/mercury时报错

问题描述 作者在安装 Flarum 的插件 extiverse/mercury 时报错&#xff0c;内容如下图所示 解决方案 ⚠警告&#xff1a;请备份所有数据再进行接下来的操作&#xff0c;此操作可能会导致网站不可用&#xff01; 报错原因&#xff1a;主要问题是在安装过程中解决依赖关系。具…

CentOS 9 (stream) 安装 Docker

1. Docker 简介 Docker 是一个开源的容器化平台&#xff0c;可帮助开发者轻松地创建、部署和运行应用程序。Docker 使开发人员能够在一个独立的容器中打包应用程序及其依赖项&#xff0c;这样他们就可以轻松地将应用程序移植到任何其他环境中。 Docker 主要由以下几个组件组成…

使用CentOS 7.6搭建HTTP隧道代理服务器

在现代网络环境中&#xff0c;HTTP隧道代理服务器因其灵活性和安全性而受到广泛关注。CentOS 7.6&#xff0c;作为一个稳定且功能强大的Linux发行版&#xff0c;为搭建此类服务器提供了坚实的基础。 首先&#xff0c;我们需要明确HTTP隧道代理的基本原理。HTTP隧道代理允许客户…

安科瑞变电站综合自动化系统在青岛海洋科技园应用——安科瑞 顾烊宇

摘 要&#xff1a;变电站综合自动化系统是将变电站内的二次设备经过功能的组合和优化设计&#xff0c;利用先进的计算机技术、通信技术、信号处理技术&#xff0c;实现对全变电站的主要设备和输、配电线路的自动监视、测量、控制、保护、并与上级调度通信的综合性自动化功能。 …