0%

FastJson 拷贝过程踩坑

前几天在项目中使用 fastjson,对对象进行修改,发现我修改了新创建的对象,但是原始的 fastjson 的内容也发生了改变。当时是在一个方法中,有个 JSONObject 对象传递进来,然后在 for 循环中重新创建一个对象,塞进数组中,下面模拟一个简单事例:

1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) {
JSONObject data = new JSONObject();
data.put("a", "a");
data.put("b", "b");
JSONObject after = new JSONObject(data);
after.put("c", "c");
System.out.println("原始数据:" + data);
System.out.println("修改后:" + after);
}

输出结果:

1
2
原始数据:{"a":"a","b":"b","c":"c"}
修改后:{"a":"a","b":"b","c":"c"}

在印象中的Java中,只要我通过 new 创建一个新的对象,那么和之前的对象数据应该就没关系了,但是我们会发现上面的代码中,我修改了新创建的对象,但是原始数据还是跟着修改了。

翻了下代码,发现了 fastjson 中这个问题的奥秘。通过下面的代码,会发现,在创建一个新的 JSONObject 对象时,赋值的对象 map 是通过 final 进行修饰的,这时想起来,final 有个特性:如果引用为引用类型数据,比如对象、数组,则该对象、数组本身可以修改,但指向该对象或数组的地址引用不能修改。

1
2
3
4
5
6
7
8
9
10
private static final int DEFAULT_INITIAL_CAPACITY = 16;
private final Map<String, Object> map;

public JSONObject(Map<String, Object> map) {
if (map == null) {
throw new IllegalArgumentException("map is null.");
} else {
this.map = map;
}
}

通过上面的例子,虽然我通过 new 创建了一个新的对象,但是新对象的地址还是指向了最原始的那个地址。

PS:不知道这个点是不是 fastjson 的开发者考虑性能问题。在我尝试使用 fastjson2时,发现已经不存在这个问题了

如果想使用 fastjson 进行拷贝数据,可以先将源对象转化成对象,再转成 JSONObject,比如下面的例子:

1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args) {
JSONObject data = new JSONObject();
data.put("a", "a");
data.put("b", "b");

JSONObject obj = JSON.parseObject(data.toJSONString());
obj.put("c", "c");
System.out.println("原始数据:" + data);
System.out.println("修改后:" + obj);

}
客官,赏一杯coffee嘛~~~~