写点什么

Java 进阶 (四)Java 反射 TypeToken 解决泛型运行时类型擦除问题

  • 2022 年 9 月 04 日
    上海
  • 本文字数:1493 字

    阅读完需:约 5 分钟

Java进阶(四)Java反射TypeToken解决泛型运行时类型擦除问题

在开发时,遇到了下面这条语句,不懂,然习之。

private List<MyZhuiHaoDetailModel> listLottery = new ArrayList<MyZhuiHaoDetailModel>();
Gson gson=new Gson();
JSONObject object=new JSONObject(callbackValue);
listLottery =  gson.fromJson(object.getString("lists"),
new TypeToken<List<MyZhuiHaoDetailModel>>() {
}.getType());
复制代码


GSON提供了 TypeToken 这个类来帮助我们捕获(capture)像List<MyZhuiHaoDetailModel>这样的泛型信息。上文创建了一个匿名内部类,这样,Java 编译器就会把泛型信息编译到这个匿名内部类里,然后在运行时就可以被 getType()方法用反射 API 提取到。


下面来看看 gson 的反序列化,Gson提供了fromJson()方法来实现从 Json 相关对象到 java 实体的方法。


在日常应用中,我们一般都会碰到两种情况,转成单一实体对象转换成对象列表或者其他结构。


先来看第一种:


比如 json 字符串为:{"name":"name0","age":0}


代码:

Person person = gson.fromJson(str, Person.class);
复制代码

提供两个参数,分别是 json 字符串以及需要转换对象的类型。


第二种,转换成列表类型:


代码:

List<Person> ps = gson.fromJson(str, new TypeToken<List<Person>>(){}.getType());
for(int i = 0; i < ps.size() ; i++)
{
     Person p = ps.get(i);
     System.out.println(p.toString());
}
复制代码

可以看到上面的代码使用了 TypeToken,它是 gson 提供的数据类型转换器,可以支持各种数据集合类型转换。


经过比较,gson 和其他现有 java json 类库最大的不同是 gson 需要序列化的实体类不需要使用 annotation 来标识需要序列化得字段,同时 gson 又可以通过使用 annotation 来灵活配置需要序列化的字段。


另外,java 反射包中的 TypeToken 类是用来解决 java 运行时泛型类型被擦除的问题的,有点不好理解,我们通过一个例子来认识什么是泛型的运行时类型擦除。

        

ArrayList<String> stringList = Lists.newArrayList();  
ArrayList<Integer> intList = Lists.newArrayList();        
System.out.println("intList type is " + intList.getClass());    
System.out.println("stringList type is " + stringList.getClass());  
System.out.println(stringList.getClass().isAssignableFrom(intList.getClass()));
复制代码

上面的代码我们声明了两个泛型的 ArrayList 类型,一个泛型的类型参数是 String,另外一个是 Integer;然后我们输出了两个泛型的 Class,并输出两个 list 的类型是否是同一个 list。我们看下输出的结果:

intList type is class java.util.ArrayListstringList type is class java.util.ArrayListtrue
复制代码

前两个输出都是 java.util.ArrayList,而第三个输出竟然是 true,也就是认为 stringList 和 intList 的类型是一样的。这就是所谓的泛型类型擦除。运行时我们不知道泛型类型的类型参数是什么了。

TypeToken 可以解决这个问题,请看下面代码:

TypeToken<ArrayList<String>> typeToken = new TypeToken<ArrayList<String>>() {}; TypeToken<?> genericTypeToken = typeToken.resolveType(ArrayList.class.getTypeParameters()[0]);System.out.println(genericTypeToken.getType());
复制代码

注意上面第一行代码使用了一个空的匿名类。第二行使用了 resolveType 方法解析出泛型类型,第三行代码打印出泛型类型,输出是:

class java.lang.String
复制代码

可以看出 TypeToken 解析出了泛型参数的具体类型。

TypeToken 的方法列表如下:


Gson 的基本使用就是这么多,至于 annotation 方面可以参考 gson 的官方文档,希望能对初学 java 和 gson 的同学有所帮助。

发布于: 刚刚阅读数: 4
用户头像

No Silver Bullet 2021.07.09 加入

岂曰无衣 与子同袍

评论

发布
暂无评论
Java进阶(四)Java反射TypeToken解决泛型运行时类型擦除问题_Java_No Silver Bullet_InfoQ写作社区