文档章节

Java中泛型集合List<T>反序列化问题及解决方法

留给明天
 留给明天
发布于 2017/06/22 00:26
字数 708
阅读 408
收藏 0

本文通过3个问题来讨论如何使用 GSON 把JSON反序列化为List。

问题1

有这样两个类:

class MyObj {
    int x;
}

class MyList {
    List<MyObj> objList = new LinkedList<>();
}

那下面的测试能通过吗?

@Test
    public void test1() {
        MyList myList = new Gson().fromJson("{objList:[]}", MyList.class);
        Assert.assertEquals(LinkedList.class, myList.objList.getClass());
    }

答案1

答案是,测试 通不过 !原因是GSON不知道objList的具体类型,因此只能选择默认的ArrayList。更详细的解释,可以参考这篇文章和ConstructorConstructor类的源代码。如果确实想让GSON创建LinkedList实例该怎么办呢?也简单,就是给objList一个更具体的类型:

class MyList {
    LinkedList<MyObj> objList = new LinkedList<>();
}

问题2

下面的测试能通过吗?

@Test
    public void test2() {
        ArrayList<?> list = new Gson().fromJson("[{x:1}]", ArrayList.class);
        Assert.assertEquals(1, list.size());
        Assert.assertEquals(MyObj.class, list.get(0).getClass());
    }

答案2

很明显,不能。因为fromJson方法不能从"[{x:1}]"参数推测出数组里放的是MyObj类型的对象,也无法从ArrayList.class参数得到这个信息。那么改成下面这样呢?

ArrayList<MyObj> list = new Gson().fromJson("[{x:1}]", ArrayList<MyObj>.class);

更糟糕,连编译都无法通过!因为Java的泛型是用 擦拭法

实现的,说白了只是编译器提供给程序员的语法糖,根本不存在ArrayList<MyObj>这样一个类。那么怎样才能让GSON反序列化出我们想要的泛型对象呢?答案是,请TypeToken帮忙:

@Test
	public void test3() {
		Type type = new TypeToken<ArrayList<MyObj>>() {}.getType();
		ArrayList<MyObj> list = new Gson().fromJson("[{x:1}]", type);
		Assert.assertEquals(1, list.size());
		Assert.assertEquals(MyObj.class, list.get(0).getClass());
	}

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

问题3

如果我想写一个通用的方法,把json反序列化成List,下面这个方法可行吗?

public static <T> ArrayList<T> jsonToList(String json, Class<T> classOfT) {
        Type type = new TypeToken<ArrayList<T>>() {}.getType();
        return new Gson().fromJson(json, type);
    }

这个测试能通过吗?

@Test
    public void test4() {
        ArrayList<MyObj> list = jsonToList("[{x:1}]", MyObj.class);
        Assert.assertEquals(1, list.size());
        Assert.assertEquals(MyObj.class, list.get(0).getClass());
    }

答案3

答案是,方法不可行(虽然能编译通过),测试通不过!还是因为Java泛型的 擦除法 ,详细的回答可以看stackoverflow上的 这个问题 。那还有办法实现jsonToList()这个通用方法呢?有的,只是稍微复杂一点:

public static <T> ArrayList<T> jsonToList(String json, Class<T> classOfT) {
	Type type = new TypeToken<ArrayList<JsonObject>>(){}.getType();
	ArrayList<JsonObject> jsonObjs = new Gson().fromJson(json, type);
	
	ArrayList<T> listOfT = new ArrayList<>();
	for (JsonObject jsonObj : jsonObjs) {
	    listOfT.add(new Gson().fromJson(jsonObj, classOfT));
	}
	
	return listOfT;
    }

分两步,先反序列化出ArrayList<JsonObject>,然后在一个个的把JsonObject转成classOfT类型的对象。

© 著作权归作者所有

共有 人打赏支持
留给明天
粉丝 0
博文 40
码字总数 18582
作品 0
深圳
私信 提问
加载中

评论(2)

留给明天
留给明天

引用来自“窗外有个蓝蓝天”的评论

用TypeToken就行了,匿名内部类可以获取泛型的具体类型
是啊,Gson可以解析带泛型的
窗外有个蓝蓝天
窗外有个蓝蓝天
用TypeToken就行了,匿名内部类可以获取泛型的具体类型
Hibernate反射DAO模式

在持久层框架中,如果我们要像简单的JDBC连接数据库那样写一个通用的Dao方法的话,那么把JDBC简单的业务逻辑搬到hibernate持久层框架中,当然是不可能的,这里主要的问题就在于hibernate持久...

zretc
2013/07/19
0
0
Java List序列化的实现

概述 java中的序列化与反序列化都要求对象实现接口(其实就是声明一下),而对于List这种动态改变的集合默认是不实现这个接口的,也就是不能直接序列化。但是数组是可以序列化的,所以我们只...

时刻在奔跑
04/17
0
0
10 道关于 Java 泛型的面试题

1.Java中的泛型是什么 ? 使用泛型的好处是什么? 这是在各种Java泛型面试中,一开场你就会被问到的问题中的一个,主要集中在初级和中级面试中。那些拥有Java1.4或更早版本的开发背景的人都知道...

蚂蚁-Declan
10/24
0
0
GSON使用笔记(3) -- 如何反序列化出List

GSON使用笔记(3) -- 如何反序列化出List 时间 2014-06-26 17:57:06 CSDN博客原文 http://blog.csdn.net/zxhoo/article/details/34856061 本文通过3个问题来讨论如何使用 GSON 把JSON反序列...

thinkyoung
2015/03/24
0
0
java基础专栏—Properties

Properties 一个持久的属性集。Properties可以保存在流中或从流中加载,Map中每个键和值都对应字符串 HashTable的子类,Map集合的方法都可以使用,线程安全 该集合没有泛型,且不能写泛型 它...

T-newcomer
2017/10/21
0
0

没有更多内容

加载失败,请刷新页面

加载更多

tomcat线程模型

Connector结构 BIO模式 NIO模式

grace_233
23分钟前
1
0
Javascript

变量定义 以$,_,字母开头 大小写敏感 var 关键字声明变量 声明未赋值undefined 数据类型 字符串,数字,布尔,数组,NULL,undefined 变量均为对象 函数 无默认值 var声明的是局部变量 函数外声明...

关元
24分钟前
1
0
文件系统、服务、防火墙、SELINUX——安全四大金刚

一提到安全,大家都会想到防火墙,和文件系统权限。而实际工作环境中,我们在Linux的安全配置,会涉及到四个级别。我们思考一个场景,你要在百度盘中存放一个文件,这个动作需要考虑下面四个...

Linux就该这么学
25分钟前
1
0
从源码角度理解Java设计模式——门面模式

一、门面模式介绍 门面模式定义:也叫外观模式,定义了一个访问子系统的接口,除了这个接口以外,不允许其他访问子系统的行为发生。 适用场景:子系统很复杂时,增加一个接口供外部访问。 优...

我叫刘半仙
35分钟前
2
0
新鲜出炉,2019最新大厂面试题总汇!

在这个互联网技术快速迭代的时代,每个程序员都知道技术对于职业发展的重要性,那些技术好的程序员不仅薪资高,而且大多数集中在一线互联网企业工作,让人感觉非常高大上的同时,也想去大厂做...

Java架构资源分享
44分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部