android:gson通过借助typetoken获取泛型参数的类型的方法

DM--Tutor DM--Tutor     2023-03-25     220

关键词:

最近在使用Google的Gson包进行Json和Java对象之间的转化,对于包含泛型的类的序列化和反序列化Gson也提供了很好的支持,感觉有点意思,就花时间研究了一下。

由于Java泛型的实现机制,使用了泛型的代码在运行期间相关的泛型参数的类型会被擦除,我们无法在运行期间获知泛型参数的具体类型(所有的泛型类型在运行时都是Object类型)。

但是有的时候,我们确实需要获知泛型参数的类型,比如将使用了泛型的Java代码序列化或者反序列化的时候,这个时候问题就变得比较棘手。

 

class Foo<T>
  T value;

Gson gson = new Gson();
Foo<Bar> foo = new Foo<Bar>();
gson.toJson(foo); // May not serialize foo.value correctly

gson.fromJson(json, foo.getClass()); // Fails to deserialize foo.value as Bar

 

对于上面的类Foo<T>,由于在运行期间无法得知T的具体类型,对这个类的对象进行序列化和反序列化都不能正常进行。Gson通过借助TypeToken类来解决这个问题。

 

TestGeneric<String> t = new TestGeneric<String>();
  t.setValue("Alo");
  Type type = new TypeToken<TestGeneric<String>>().getType();
  
  String gStr = GsonUtils.gson.toJson(t,type);
  System.out.println(gStr);
  TestGeneric t1 = GsonUtils.gson.fromJson(gStr, type);
  System.out.println(t1.getValue());
 

 

TypeToken的使用非常简单,如上面的代码,只要将需要获取类型的泛型类作为TypeToken的泛型参数构造一个匿名的子类,就可以通过getType()方法获取到我们使用的泛型类的泛型参数类型。

下面来简单分析一下原理。

要获取泛型参数的类型,一般的做法是在使用了泛型的类的构造函数中显示地传入泛型类的Class类型作为这个泛型类的私有属性,它保存了泛型类的类型信息。

 

public class Foo<T>
 
 public Class<T> kind;
 
 public Foo(Class<T> clazz)
  this.kind = clazz;
 
 
 public T[] getInstance()
  return (T[])Array.newInstance(kind, 5);
 
 
 public static void main(String[] args)
  Foo<String> foo = new Foo(String.class);
  String[] strArray = foo.getInstance();
 

 

这种方法虽然能解决问题,但是每次都要传入一个Class类参数,显得比较麻烦。Gson库里面对于这个问题采用了了另一种解决办法。

同样是为了获取Class的类型,可以通过另一种方式实现:

文章出自:http://www.ishang123.com/jishubowen/java/2012-07-28/100.html

 

public abstract class Foo<T>
 
 Class<T> type;
 
 public Foo()
  this.type = (Class<T>) getClass();
 

        public static void main(String[] args)
  
  Foo<String> foo = new Foo<String>();
  Class mySuperClass = foo.getClass();

 
 

 

 

声明一个抽象的父类Foo,匿名子类将泛型类作为Foo的泛型参数传入构造一个实例,再调用getClass方法获得这个子类的Class类型。

这里虽然通过另一种方式获得了匿名子类的Class类型,但是并没有直接将泛型参数T的Class类型传进来,那又是如何获得泛型参数的类型的呢,这要依赖Java的Class字节码中存储的泛型参数信息。Java的泛型机制虽然在运行期间泛型类和非泛型类都相同,但是在编译java源代码成class文件中还是保存了泛型相关的信息,这些信息被保存在class字节码常量池中,使用了泛型的代码处会生成一个signature签名字段,通过签名signature字段指明这个常量池的地址。

关于class文件中存储泛型参数类型的具体的详细的知识可以参考这里:http://stackoverflow.com/questions/937933/where-are-generic-types-stored-in-java-class-files

JDK里面提供了方法去读取这些泛型信息的方法,再借助反射,就可以获得泛型参数的具体类型。同样是对于第一段代码中的foo对象,通过下面的代码可以得到foo<T>中的T的类型:

 

Type mySuperClass = foo.getClass().getGenericSuperclass();
  Type type = ((ParameterizedType)mySuperClass).getActualTypeArguments()[0];
                System.out.println(type);
 

 

        
运行结果是class java.lang.String。

分析一下这段代码,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类都会实现这个接口。

实际运用中还要考虑比较多的情况,比如获得泛型参数的个数避免数组越界等,具体可以参看Gson中的TypeToken类及ParameterizedTypeImpl类的代码。

 

未解决的参考:TypeToken

】未解决的参考:TypeToken【英文标题】:Unresolvedreference:TypeToken【发布时间】:2021-08-1723:29:43【问题描述】:我是第一次使用JSON,但遇到了问题。当我尝试使用和导入TypeToken时,我收到错误“Unresolvedreference:TypeToken”。我的代码i... 查看详情

如何在 Kotlin 中将 TypeToken + 泛型与 Gson 一起使用

】如何在Kotlin中将TypeToken+泛型与Gson一起使用【英文标题】:HowtouseTypeToken+genericswithGsoninKotlin【发布时间】:2016-01-2715:44:26【问题描述】:我无法从自定义类(Turns)中获取泛型类型列表:valturnsType=TypeToken<List<Turns>>().typeval... 查看详情

typetoken获取运行时泛型类型

 最近正好使用到了guava的TypeToken来获取泛型类型使用方法: returnnewTypeToken<T>(thisClass).getRawType();  网上冲了一浪,发现关于泛型,有前人给出的总结:Java泛型有这么一种规律: 位于声明一侧的,源码里写... 查看详情

gson的typetoken

 需要解析json,看了gson的文档,发现有Typetype=newTypeToken<List<User>>(){}.getType();来获取需要序列化的对象的类信息,这里主要记录两个知识点一、匿名内部类什么情况下需要使用匿名内部类?如果满足下面的一些条件,... 查看详情

具有动态 ArrayList 项类型的 Gson TypeToken

】具有动态ArrayList项类型的GsonTypeToken【英文标题】:GsonTypeTokenwithdynamicArrayListitemtype【发布时间】:2014-01-1311:04:03【问题描述】:我有这个代码:TypetypeOfObjectsList=newTypeToken<ArrayList<myClass>>().getType();List<myClass>obje 查看详情

Android - GSon + RetroFit 中的继承和抽象类

】Android-GSon+RetroFit中的继承和抽象类【英文标题】:Android-InheritanceandabstractclassesinGSon+RetroFit【发布时间】:2015-09-2719:36:32【问题描述】:我有以下类层次结构publicabstractclassSyncModel@Expose@SerializedName("id")privateLongglobalId;@Exposeprotect 查看详情

使用 gson 反序列化时将 TypeToken 转换为 Type 时出错

】使用gson反序列化时将TypeToken转换为Type时出错【英文标题】:ErrorcastingTypeTokentoTypewhendeserializingwithgson【发布时间】:2012-07-1406:21:44【问题描述】:我有一个类可以使用此函数反序列化泛型的ArrayList,正如该线程的第一个答案中... 查看详情

Android gson 反序列化成列表

】Androidgson反序列化成列表【英文标题】:Androidgsondeserializationintolist【发布时间】:2011-12-1900:55:09【问题描述】:我正在尝试将json字符串解析为列表或数组列表。我有以下json响应来自我为Android项目创建的WCFRESTful服务["Class":"Lore... 查看详情

win7基础环境变量的配置借助变量,通过拼接来添加路径

 注意事项:博文内容仅供参考,不可用于其他用途。     (我就是想把这个路径加到环境变量中,以此来简化javajavac的使用步骤)  (需要新建一个中间变量)      (就像字符串变量... 查看详情

借助循环(python)拆分数据框

...时间】:2021-10-1300:48:27【问题描述】:我需要帮助。我想通过一个DF。部分我的用户有2个团队(在行中用逗号分隔)。我用逗号将它们分开,并将它们写在新列Team_1和Team_2中。如果只有一个团队,则团队名称进入团队1。importnumpy... 查看详情

gcahce事物不够,借助binlog追上(代码片段)

...的集群保持一致:修复grastate.dat文件的方式这里略,直接通过wsrep_recovery即可修复grastate.dat文件后,取其中的seqno(假设为737),然后借助seqno找到其他节点binlong的start-position:[[email protecte 查看详情

selenium----xpath的使用

XpathXpath是XML的路径语言,就是通过元素的路径来查找标签元素借助工具可以借助火狐浏览器的Firebug和Firepath插件来练习Xpath定位方法固定格式://*[@属性名=‘‘]1.xpath支持id,class,name定位  通过id定位,如://*[@id=‘i1‘]  ... 查看详情

借助loganalyzer打造轻量级数据库审计日志平台

...合规性管理,对数据库遭受到的风险行为进行实时告警。通过对用户访问数据库行为记录、分析和汇报,来帮助DBA事后生成合规报告、事故追根溯源,同时通过搜索技术提供高效查询审计报告,定位事件原因,以便日后查询、分... 查看详情

java解析json字符串

...nteractPrizeList = gson.fromJson(interactPrizeAll, new TypeToken<List<InteractPrize>>().getType()); //TypeToken,它是gson提供的数据类型转换器,可以支持各种数据集合类型转换 for(int i = 0; i <&n 查看详情

借助flexpaper实现word在线预览和打印

...案的实现过程主要是先将word文档转换成pdf文档,接着再通过SWFTOOLS工具将pdf文档转换成swf文件,然后flexpaper加载这些swf文件进行展示。访问 查看详情

借助活字格快速搭建企业文档管理系统

...第一步、根据业务需求,设计所有的数据表 第二步、通过资料ID,完成设计表之间关系的联接 第三步、根据系统功能需求,完成系统页面的基本设计 第四步、设计母版页,包含各项功能所需使用的 查看详情

android开发笔记(一百七十六)借助fileprovider发送彩信(代码片段)

...性化的定制开发。为了把更多的文件信息开放出来,Android设计了专门的媒体共享库,允许开发者通过内容组件从中获取更详细的媒体信息。就图片而言,相册媒体库的路径为MediaStore.Ima 查看详情

android开发笔记(一百七十六)借助fileprovider发送彩信(代码片段)

...性化的定制开发。为了把更多的文件信息开放出来,Android设计了专门的媒体共享库,允许开发者通过内容组件从中获取更详细的媒体信息。就图片而言,相册媒体库的路径为MediaStore.Ima 查看详情