Java-TypeToken原理及泛型擦除

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!

三个问题

为什么要用TypeToken来定义反序列化的类型?正如上面说的,如果直接把List<Map<String, Foo>>的类型传过去,但是因为运行时泛型被擦除了,所以得到的其实是List,那么后面的Gson就不知道要转成Map<String, Foo>类型了,这时Gson会默认转成LinkedTreeMap类型。

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

为什么要通过子类来获取泛型的类型?这是TypeToken能够获取到泛型类型的关键,这是一个巧妙的方法。这个想法是这样子的,既然像List这样中的泛型会被擦除掉,那么我用一个子类SubList extends List这样的话,在JVM内部中会不会把父类泛型的类型给保存下来呢?我这个子类需要继承的父类的泛型都是已经确定了的呀,果然,JVM是有保存这部分信息的,它是保存在子类的Class信息中,具体看:https://stackoverflow.com/questions/937933/where-are-generic-types-stored-in-java-class-files 那么我们怎么获取这部分信息呢?还好,Java有提供API出来:

Type mySuperClass = foo.getClass().getGenericSuperclass();

Type type = ((ParameterizedType)mySuperClass).getActualTypeArguments()[0];

System.out.println(type);

分析一下这段代码,Class类的getGenericSuperClass()方法的注释是:

Returns the Type representing the direct superclass of the entity (class, interface, primitive type or void) represented by thisClass. If the superclass is a parameterized type, the Type object returned must accurately reflect the actual type parameters used in the source code. The parameterized type representing the superclass is created if it had not been created before. See the declaration of ParameterizedType for the semantics of the creation process for parameterized types. If thisClass represents either theObject class, an interface, a primitive type, or void, then null is returned. If this object represents an array class then theClass object representing theObject class is returned

概括来说就是对于带有泛型的class,返回一个ParameterizedType对象,对于Object、接口和原始类型返回null,对于数 组class则是返回Object.class。ParameterizedType是表示带有泛型参数的类型的Java类型,JDK1.5引入了泛型之 后,Java中所有的Class都实现了Type接口,ParameterizedType则是继承了Type接口,所有包含泛型的Class类都会实现 这个接口。

自己调试一下就知道它返回的是什么了。

原理

核心的方法就是刚刚说的那两句,剩下的就很简单了。我们看看TypeToken的getType方法

public final Type getType() {

//直接返回type

return type;

}

看type的初始化

//注意这里用了protected关键字,限制了只有子类才能访问

protected TypeToken() {

this.type = getSuperclassTypeParameter(getClass());

this.rawType = (Class<? super T>) G s o n Gson GsonTypes.getRawType(type);

this.hashCode = type.hashCode();

}

//getSuperclassTypeParameter方法

//这几句就是上面的说到

static Type getSuperclassTypeParameter(Class<?> subclass) {

Type superclass = subclass.getGenericSuperclass();

if (superclass instanceof Class) {

throw new RuntimeException(“Missing type parameter.”);

}

ParameterizedType parameterized = (ParameterizedType) superclass;

//这里注意一下,返回的是Gson自定义的,在 G s o n Gson GsonTypes里面定义的TypeImpl等,这个类都是继承Type的。

return G s o n Gson GsonTypes.canonicalize(parameterized.getActualTypeArguments()[0]);

}

总结


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

读者福利

感谢你看到了这里!

我这边整理很多2021最新Java面试题(含答案)和Java学习笔记,如下图

在这里插入图片描述

上述的面试题答案小编都整理成文档笔记。 同时也还整理了一些面试资料&最新2021收集的一些大厂的面试真题(都整理成文档,小部分截图)免费分享给大家,有需要的可以 点击进入暗号:CSDN!免费分享~

最后

小编精心为大家准备了一手资料

以上Java高级架构资料、源码、笔记、视频。Dubbo、Redis、设计模式、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术

【附】架构书籍

  1. BAT面试的20道高频数据库问题解析
  2. Java面试宝典
  3. Netty实战
  4. 算法

BATJ面试要点及Java架构师进阶资料

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!
面试要点及Java架构师进阶资料**

[外链图片转存中…(img-BthtYnVD-1714436128910)]

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!

  • 20
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值