码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 掌握 TypeToken 原理及泛型擦除


    目录

    1、泛型擦除

    为什么选择这种实现机制?不擦除不行么?

    2、TypeToken

    1、为什么要用TypeToken来定义反序列化的类型?

    2、为什么带有大括号{}?

     3、为什么要通过子类来获取泛型的类型?

    3、原理


    1、泛型擦除

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

    代码测试

    1. @Test
    2. public void test(){
    3. ArrayList list1 = new ArrayList<>();
    4. ArrayList list2 = new ArrayList<>();
    5. System.out.println(list1.getClass());
    6. System.out.println(list2.getClass());
    7. }

    为什么选择这种实现机制?不擦除不行么?

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

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

    2、TypeToken

    使用过Gson的同学都知道在反序列化时需要定义一个TypeToken类型,像这样

    1. Type type = new TypeToken>() {}.getType();
    2. List list1 = gson.fromJson(listJsonString, type);

    三个问题

    1、为什么要用TypeToken来定义反序列化的类型?

    正如上面说的,如果直接把 ArrayList 的类型传过去,因为运行时泛型被擦除了,所以得到的其实是 ArrayList ,那么后面的Gson就不知道要转成 ArrayList 类型了。

    2、为什么带有大括号{}?

    这个大括号就是精髓所在。大家都知道,在Java语法中,在这个语境,{}是用来定义匿名类,这个匿名类是继承了TypeToken类,它是TypeToken的子类。

    测试 

    1. @Test
    2. public void test2(){
    3. System.out.println(new TypeToken>() {}.getClass().getSuperclass());
    4. }

     结果

     3、为什么要通过子类来获取泛型的类型?

    这是TypeToken能够获取到泛型类型的关键,这是一个巧妙的方法。这个想法是这样子的,既然像ArrayList 这样中的泛型会被擦除掉,那么我用一个子类 SubList extends ArrayList这样的话,在JVM内部中会不会把父类泛型的类型给保存下来呢?

    我这个子类需要继承的父类的泛型都是已经确定了的呀,果然,JVM是有保存这部分信息的,它是保存在子类的Class信息中。

    那么我们怎么获取这部分信息呢?还好,Java有提供API出来

    1. public class TestMethod {
    2. @Test
    3. public void test1(){
    4. Student student = new Student();
    5. /**
    6. * getGenericSuperclass()获得带有泛型的父类
    7. * Type是 Java 编程语言中所有类型的公共高级接口。它们包括原始类型、参数化类型、数组类型、类型变量和基本类型。
    8. */
    9. Type mySuperClass = student.getClass().getGenericSuperclass();
    10. Type type = ((ParameterizedType) mySuperClass).getActualTypeArguments()[0];
    11. System.out.println(type);
    12. }
    13. }
    14. class Student extends ArrayList>{
    15. }

     

     概括来说就是对于带有泛型的class,返回一个ParameterizedType对象,对于Object、接口和原始类型返回null,对于数组class则是返回Object.class。

    ParameterizedType是表示带有泛型参数的类型的Java类型,JDK1.5引入了泛型之 后,Java中所有的Class都实现了Type接口,ParameterizedType则是继承了Type接口,所有包含泛型的Class类都会实现 这个接口。

    3、原理

    getType方法

    1. public final Type getType() {
    2. return this.type;
    3. }

    type的初始化

    protected的作用范围是在同一包内可被访问和继承。不同包内,子类可继承,非子类不能访问

    由于是第三方 jar 包,所以只有子类才能访问。

    1. protected TypeToken() {
    2. this.type = getSuperclassTypeParameter(getClass());
    3. this.rawType = (Classsuper T>) $Gson$Types.getRawType(type);
    4. this.hashCode = type.hashCode();
    5. }

    getSuperclassTypeParameter方法

    里面的代码就是上面说到的获取父类泛型参数的方法

    1. static Type getSuperclassTypeParameter(Class subclass) {
    2. Type superclass = subclass.getGenericSuperclass();
    3. if (superclass instanceof Class) {
    4. throw new RuntimeException("Missing type parameter.");
    5. }
    6. ParameterizedType parameterized = (ParameterizedType) superclass;
    7. //这里注意一下,返回的是Gson自定义的,这个类是继承Type的。
    8. return Types.canonicalize(parameterized.getActualTypeArguments()[0]);
    9. }

    在了解原理之后,相信大家都知道怎么去获取泛型的类型了。

    参考文章:掌握 Java-TypeToken 原理及泛型擦除-Java知音 (javazhiyin.com)

  • 相关阅读:
    linux无界面手敲命令笔记
    KiKi知道了什么是质数,他现在想知道所有三位整数中,有多少个质数
    【老生谈算法】matlab实现PLS算法源码——PLS算法
    Android面试冲刺:2022全新面试题——剑指Offer(备战金九银十)
    一文道清什么是SPL
    python调用GPT实现:智能用例生成工具
    台达PLC出现通信错误或通信超时或下载时提示机种不符的解决办法总结
    1. RxJava概述
    ES6 入门教程 6 正则的扩展 6.10 Unicode 属性类 & 6.11 v 修饰符:Unicode 属性类的运算 & 6.12 具名组匹配
    Excel 制作中式排名的方法
  • 原文地址:https://blog.csdn.net/qq_51409098/article/details/126224264
    • 最新文章
    • 攻防演习之三天拿下官网站群
      数据安全治理学习——前期安全规划和安全管理体系建设
      企业安全 | 企业内一次钓鱼演练准备过程
      内网渗透测试 | Kerberos协议及其部分攻击手法
      0day的产生 | 不懂代码的"代码审计"
      安装scrcpy-client模块av模块异常,环境问题解决方案
      leetcode hot100【LeetCode 279. 完全平方数】java实现
      OpenWrt下安装Mosquitto
      AnatoMask论文汇总
      【AI日记】24.11.01 LangChain、openai api和github copilot
    • 热门文章
    • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
      奉劝各位学弟学妹们,该打造你的技术影响力了!
      五年了,我在 CSDN 的两个一百万。
      Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
      面试官都震惊,你这网络基础可以啊!
      你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
      心情不好的时候,用 Python 画棵樱花树送给自己吧
      通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
      13 万字 C 语言从入门到精通保姆级教程2021 年版
      10行代码集2000张美女图,Python爬虫120例,再上征途
    Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
    正则表达式工具 cron表达式工具 密码生成工具

    京公网安备 11010502049817号