在入门配置《Fastjson入门配置及基本API介绍》一讲中,可以了解到使用Fastjson对普通对象进行序列化处理时,操作起来很简单。
除了处理普通对象,Fastjson还可以对Java集合、数组等进行序列化处理。
本篇内容基于Fastjson 1.2.62版本,马上开始学习吧。
元素为基本类型
List的序列化
和处理普通对象一样,对List的序列化和反序列化,也分别是通过toJSONString方法和parseObject方法来实现的。
/**
* List序列化与反序列化
*/
@Test
public void serializeList() {
List<String> list = new ArrayList<>();
list.add("sam");
list.add("fanny");
System.out.println("List对象:" + list);
// 将List对象序列化
System.out.println("List对象序列化:" + JSON.toJSONString(list));
// 将数组对应的字符串反序列化为List对象
String str = "[\"sam2\",\"fanny2\"]";
System.out.println("反序列化为List对象:" + JSON.parseObject(str, List.class));
}
执行结果:
List对象:[sam, fanny]
List对象序列化:["sam","fanny"]
反序列化为List对象:[sam2, fanny2]
Set的序列化
Set的序列化操作和List非常相似,主要差异是Set本身是不重复且无序的,而List是可重复且有序的。
/**
* Set序列化与反序列化
*/
@Test
public void serializeSet() {
Set<String> set = new HashSet<>();
set.add("sam");
set.add("fanny");
System.out.println("Set对象:" + set);
// 将Set对象序列化
System.out.println("Set对象序列化:" + JSON.toJSONString(set));
// 将数组对应的字符串反序列化为Set对象
String str = "[\"sam2\",\"fanny2\"]";
System.out.println("反序列化为Set对象:" + JSON.parseObject(str, Set.class));
}
执行结果:
Set对象:[fanny, sam]
Set对象序列化:["fanny","sam"]
反序列化为Set对象:[sam2, fanny2]
Map的序列化
使用同样的方法,对Map进行序列化处理。
/**
* Map序列化与反序列化
*/
@Test
public void serializeMap() {
Map<String, Integer> map = new HashMap<>();
map.put("sam", 26);
map.put("fanny", 1);
System.out.println("Map对象:" + map);
// 将Map对象序列化
System.out.println("Map对象序列化:" + JSON.toJSONString(map));
// 将数组对应的字符串反序列化为Map对象
String str = "{\"fanny\":1,\"sam\":26}";
System.out.println("反序列化为Map对象:" + JSON.parseObject(str, Map.class));
}
执行结果:
Map对象:{fanny=1, sam=26}
Map对象序列化:{"fanny":1,"sam":26}
反序列化为Map对象:{fanny=1, sam=26}
数组的序列化
使用同样的方法,对数组进行序列化处理。
/**
* 数组的序列化与反序列化
*/
@Test
public void serializeArray() {
String[] array = {"sam", "fanny"};
// 将数组对象序列化
System.out.println("数组对象序列化:" + JSON.toJSONString(array));
// 将数组对应的字符串反序列化为数组对象
String str = "[\"sam2\",\"fanny2\"]";
String[] newArray = JSON.parseObject(str, String[].class);
System.out.println("反序列化为数组对象. size: " + newArray.length +
", value: [" + newArray[0] + "," + newArray[1] + "]");
}
执行结果:
数组对象序列化:["sam","fanny"]
反序列化为数组对象. size: 2, value: [sam2,fanny2]
元素为自定义类型
如果集合的元素为非基本类型,那么在进行反序列化后,结果可能不符合预期。
首先,自定义一个类:
public class People {
private String name;
private int age;
// 此处省略了getter和setter方法
@Override
public String toString() {
return "People [name=" + name + ", age=" + age + "]";
}
}
接着进行反序列化:
/**
* 如果集合的元素为非基本类型,那么在进行反序列化后,结果可能不符合预期。
*/
@Test
public void deserializeNonPrimitive() {
People p1 = new People();
p1.setName("sam");
p1.setAge(26);
List<People> list = new ArrayList<>();
list.add(p1);
String jsonString = JSON.toJSONString(list); // [{"name":"sam","age":26}]
// 下面看看反序列化的效果
List<People> newList = JSON.parseObject(jsonString, List.class);
// List<People> newList = JSON.parseObject(jsonString, List<People>.class); // 错误的泛型用法
// 正常输出[{"name":"sam","age":26}]
System.out.println(newList.toString());
// 抛出异常:java.lang.ClassCastException: com.alibaba.fastjson.JSONObject cannot be cast to People
System.out.println(newList.get(0).toString());
}
执行结果:
[{"name":"sam","age":26}]
然后抛出异常:
java.lang.ClassCastException: com.alibaba.fastjson.JSONObject cannot be cast to People
为什么newList.toString()能够正常输出,而newList.get(0).toString()却会抛出异常呢?
从异常栈可以看到,反序列化后List中的元素类型为JSONObject,而不是People。
这是因为在反序列化的时候,指定的类型为List.class,并没有明确元素的类型,因此Fastjson默认使用了JSONObject来对KV值进行反序列化。
那么,把List.class改为List<People>.class
可以吗?答案是否定的,因为在Java中是不支持这种用法的,这与泛型的类型擦除规则有关。
通过TypeReference解决类型无法传递问题
为了解决这个问题,Fastjson引入了一个类TypeReference,用来传递这种复杂的泛型类型。
TypeReference类的声明带有一个泛型类型:
public class TypeReference<T> {...}
其基本用法,是创建一个空实现的实例,T传入需要反序列化对应类的class对象。
然后将该实例传入parseObject的TypeReference<T>
参数中。
/**
* 反序列化时,使用TypeReference传递复杂的泛型类型
*/
@Test
public void deserializeNonPrimitiveWithTypeReference() {
// 反序列化List<People>
String jsonString = "[{\"name\":\"sam\",\"age\":26}]";
List<People> newList = JSON.parseObject(jsonString, new TypeReference<List<People>>(){});
System.out.println("List:" + newList.get(0).toString());
// 反序列化Map<String, People>
String jsonString2 = "{\"xiaoming\":{\"name\":\"cy\",\"age\":1},\"xiaoli\":{\"name\":\"fanny\",\"age\":20}}";
Map<String, People> map = JSON.parseObject(jsonString2, new TypeReference<Map<String, People>>(){});
People p1 = map.get("xiaoming");
People p2 = map.get("xiaoli");
System.out.println("xiaoming:" + p1.toString());
System.out.println("xiaoli:" + p2.toString());
}
执行结果:
List:People [name=sam, age=26]
xiaoming:People [name=cy, age=1]
xiaoli:People [name=fanny, age=20]
TypeReference类的基本思想,来源于这篇文章:http://gafter.blogspot.com/2006/12/super-type-tokens.html
小结
Fastjson除了处理普通对象,还可以对Java集合、数组等进行序列化处理。
如果需要"反序列化集合"的元素为非基本类型,可以通过创建一个空实现的TypeReference实例,将需要反序列化的集合带上泛型信息传递进去,以解决泛型信息无法传递的问题。