`
123003473
  • 浏览: 1064197 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

Gson通过借助TypeToken获取泛型参数的类型的方法

    博客分类:
  • java
 
阅读更多
[size=medium]最近在使用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的类型,可以通过另一种方式实现:

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类的代码。[/size]

【转载地址】
http://www.blogjava.net/brock/archive/2012/08/01/384520.html
分享到:
评论

相关推荐

    gson解析泛型和将泛型转为json字符串

    当我们需要从JSON字符串反序列化到泛型类型时,可以创建一个泛型类型的`Gson`对象或使用`fromJson()`方法。例如,如果你有一个泛型列表`List&lt;T&gt;`,你可以这样做: ```java Type listType = new TypeToken...

    json字符串实体bean或者List互转(gson和jackson,支持泛型)

    json字符串实体bean或者List互转(gson和jackson,支持泛型),支持json的格式化,所需要的包在代码也有说明。还有少的可以告知我,谢谢

    Gson解析Json 泛型

    Gson解析json,实现泛型解析数据,根据用户传入的类型,解析称用户需要的,Common \CommonList 里面的status message data相关的约定可以更具开发者与服务器的约定修改

    Gson+JsonPath+泛型的Json工具类

    Json解析工具类完善一下,使用GSON+JsonPath+泛型来提高自己写JSON解析的效率 http://blog.csdn.net/b275518834/article/details/49819831

    Gson简要使用笔记

    `TypeToken` 是 Gson 提供的一个泛型安全的类型引用,用于在运行时捕获和表示类型信息。 除了默认行为外,Gson 还支持通过注解(Annotations)进行更精细的控制。例如,你可以使用 `@Expose` 注解来指定哪些字段...

    om.google.gson.Gson Gson maven依赖

    5. **类型安全的转换**:Gson的`fromJson()`方法支持传入`Type`或`TypeToken`参数,以确保反序列化的对象类型正确。 6. **流式API**:对于大型JSON数据,Gson提供了流式解析API,可以有效地处理大文件或网络流。 7...

    使用gson解析json

    处理泛型类型时,可以使用`TypeToken`来帮助Gson识别真实类型: ```java List&lt;User&gt; userList = gson.fromJson(jsonArrayString, new TypeToken&lt;List&lt;User&gt;&gt;(){}.getType()); ``` 五、注意事项 1. 数据类型匹配:...

    Gson基本使用方法

    当你需要将JSON解析到泛型类型时,可以使用`TypeToken`。例如,解析一个`List&lt;Person&gt;`: ```java Type listType = new TypeToken&lt;List&lt;Person&gt;&gt;(){}.getType(); List&lt;Person&gt; people = gson.fromJson...

    Gson实战.doc

    - 当处理泛型类型时,如List或Map,需要提供具体的TypeToken来准确地反序列化。 - 示例中的`toJsonWithGson(Object obj, Type type)`方法即展示了如何处理带有泛型参数的类型。 #### 四、Gson工具类详解 根据...

    gson源码.rar

    1. **TypeToken**: 这个类用于存储泛型类型信息,因为Java的泛型在编译后会被擦除,TypeToken通过Class对象和参数化类型信息组合在一起,保存了泛型的实际类型信息。 2. **JsonSerializer&lt;T&gt; 和 JsonDeserializer**...

    com.google.gson.Gson 2.8.1 2.8.2 jar包 gson

    1. **类型安全的序列化与反序列化**:Gson允许开发者通过`Gson.toJson()`和`Gson.fromJson()`方法轻松地将Java对象转换为JSON字符串,反之亦然。这个过程是类型安全的,因为Gson会根据对象的类信息自动处理数据类型...

    gson gson gson

    10. **类型安全的泛型**: Gson可以安全地处理泛型类型,避免运行时类型转换异常。 通过以上知识点,开发者可以充分利用Gson进行JSON数据的处理,无论是将Java对象转换为JSON以便在网络间传输,还是从接收到的JSON...

    Gson工具类JsonUtils

    通过这些方法,JsonUtils工具类简化了Gson的使用,提高了代码的可读性和可维护性。开发者可以快速地在Java对象和JSON数据之间切换,无需关注底层实现细节。在项目中集成JsonUtils,可以极大地提升开发效率,同时保证...

    gson源码与文档,集成多枚举类型统一序列化/反序列化处理

    Gson的核心类是`Gson`,它提供了`toJson()`和`fromJson()`两个方法,分别用于对象到JSON和JSON到对象的转换。然而,在处理枚举类型时,默认的Gson行为可能会有所局限,因为它通常只能处理枚举的名称(即枚举常量的...

    gson-2.6.2.jar包(com.google.code.gson:gson:2.6.2)

    - **类型转换的控制**:Gson允许开发者指定特定的类型转换规则,例如使用`TypeToken`来处理泛型类型。 - **字段映射的自定义**:通过注解如`@Expose`和`@SerializedName`,可以控制哪些字段参与序列化和反序列化,...

    非常详细的gson使用方法

    在Android开发中,Gson库是Google提供的一款强大的JSON处理工具,它允许我们将Java对象转换为对应的JSON字符串,同时也能够将JSON数据解析成相应的Java对象。这篇详细的文章将深入探讨如何利用Gson进行高效的JSON...

    利用Gson.jar快速将对象类型转换为Json

    - **类型适配器**:通过创建`TypeAdapter`并注册到`GsonBuilder`,可以完全控制特定类型的序列化和反序列化过程。 7. **注意事项** - 当对象包含循环引用时,Gson可能会导致无限递归错误。可以使用`@Expose`注解...

    Android Gson解析案例

    6. **遍历和提取数据**:通过`getAs...()`方法获取不同类型的JsonElement并进行操作。 ```java for (Map.Entry, JsonElement&gt; entry : jsonObject.entrySet()) { String key = entry.getKey(); JsonElement value ...

    Gson 2.3.1

    此外,它还能处理嵌套的JSON结构,以及泛型类型。 5. **类型转换**: Gson提供了一些高级特性,如`TypeToken`,用于处理不确定类型的泛型。`GsonBuilder`则允许自定义序列化和反序列化的配置,比如日期格式、字段...

    com.google.gson.Gson-2.8.2

    6. **泛型支持**:Gson能够处理带有类型参数的类,即使这些类型信息在运行时可能丢失。 7. **配置选项**:通过`GsonBuilder`,可以设置一系列配置选项,比如是否忽略未知字段、是否启用非公共字段序列化等,以适应...

Global site tag (gtag.js) - Google Analytics