转眼间,一年的时间又飞逝而过,2020在疫情中已悄然来到了年末。走过2020,再回首,思考亦多,感慨亦多,收获亦多。“忙并收获着,累并快乐着”成了心曲的主旋律,常鸣耳盼。
自来到上海以来,在公司领导的精心培育和教导下,通过自身的不断努力,无论是思想上、学习上还是工作上,都取得了长足的发展和巨大的收获,这和领导的关心以及身边同事的帮助是分不开的,在今后的工作中我会继续努力,尽我所能把工作做好,回馈公司。
关注公众号的小伙伴应该知道我最近在做的分仓项目,分享一个好消息,我们下周准备发布上线了,感谢所有团队的小伙伴,一起奋斗的这段时光,让人留恋。今天想跟大家分享的是一个编程技巧,json序列化对java开发的小伙伴来说应该是非常熟悉,我在项目中喜欢使用Google的Gson来处理序列化。之前有分享过一篇文章Java 泛型入坑,里面有介绍到,java的泛型是在编译期,运行时已被擦除掉了。即List<String>和List<Integer>在运行时其实都是List<Object>类型。那你们有思考过这样的一段代码是如何被反序列化的?
如果没有
TypeToken
的声明处理,肯定会出现
Fails to deserialize
的错误,由于在运行期间无法得知T的具体类型,对这个类的对象进行序列化和反序列化都不能正常进行。Gson通过借助TypeToken类来解决这个问题。
TypeToken的使用非常简单,如上面的代码,只要将需要获取类型的泛型类作为TypeToken的泛型参数构造一个匿名的子类,就可以通过getType()方法获取到我们使用的泛型类的泛型参数类型。
原理分析
我们看看TypeToken的源码,先看下getType的方法:
看下type的初始化:
通过Class类的getGenericSuperClass()方法来处理返回type信息,对于带有泛型的class,返回一个ParameterizedType对象。
1. 带有大括号{}如何理解?这个大括号就是精髓所在。大家都知道,在Java语法中,在这个语境,{}是用来定义匿名类,这个匿名类是继承了TypeToken类,它是TypeToken的子类;
2. 为什么要通过子类来获取泛型的类型?这是TypeToken能够获取到泛型类型的关键,这是一个巧妙的方法。这个想法是这样子的,既然像List<String>这样中的泛型会被擦除掉,那么我用一个子类SubList extends List<String>这样的话,在JVM内部中会不会把父类泛型的类型给保存下来呢?我这个子类需要继承的父类的泛型都是已经确定了的呀,果然,JVM是有保存这部分信息的,它是保存在子类的Class信息中。Java的泛型机制虽然在运行期间泛型类和非泛型类都相同,但是在编译java源代码成 class文件中还是保存了泛型相关的信息,这些信息被保存在class字节码常量池中,使用了泛型的代码处会生成一个signature签名字段,通过 签名signature字段指明这个常量池的地址;
3. ParameterizedType是表示带有泛型参数的类型的Java类型,JDK1.5引入了泛型之 后,Java中所有的Class都实现了Type接口,ParameterizedType则是继承了Type接口,所有包含泛型的Class类都会实现 这个接口。
实际运用中还要考虑比较多的情况,比如获得泛型参数的个数避免数组越界等,具体可以参看Gson中的TypeToken类及ParameterizedTypeImpl类的代码。
总结
今天带大家了解下Gson如何处理含有泛型的数据类型序列化分析,在了解原理之后,相信大家都知道怎么去获取泛型的类型了。
长按关注,欢迎一起探讨技术