Fastjson序列化集合和数组

在入门配置《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参数中。

/**
 * 反序列化时,使用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实例,将需要反序列化的集合带上泛型信息传递进去,以解决泛型信息无法传递的问题。

参考

《轻松学习Fastjson》

https://github.com/alibaba/fastjson


---转载本站文章请注明作者和出处 996极客教程(996geek.com),请勿用于任何商业用途---

留下评论