之前遇到一些关于两个引用类型是否指向同一个对象的问题,如下定义的\(ResponseObject\)中的,在这个类中,先将 \(data\) 从 \(jsonObject\) 中取出,随后所有的操作都从 \(data\) 中进行操作。
之前一直以为 \(jsonObject\) 中的 \(data\) 无论如何都是会跟着外面的 \(data\) 一起发生变化的,实际上并不一定。
class ResponseObject {
public JSONObject data;
private JSONObject jsonObject;
ResponseObject(JSONObject jsonObject) {
this.data = jsonObject.getJSONObject("data");
this.jsonObject = jsonObject;
}
public void put(String key, Object value) {
if (data == null) {
data = new JSONObject();
this.jsonObject.put("data", data);
}
data.put(key, value);
}
public JSONObject getData() {
return this.jsonObject.getJSONObject("data");
}
}
按道理来说, \(jsonObject\) 中的 \(data\) 和外面的 \(data\) 指向的是同一个对象,也就是说他们的地址是相同的。
进行测试
public class Test {
public static void main(String[] args) {
JSONObject jsonObject = new JSONObject();
JSONObject data = new JSONObject();
jsonObject.put("data", data);
ResponseObject t = new ResponseObject(jsonObject);
JSONObject bearObj = new JSONObject();
t.put("bear", bearObj);
System.out.println(System.identityHashCode(t.getData()));
System.out.println(System.identityHashCode(t.data)); //不能仅用hashCode()来判断,若复写了hashCode()则输出的就不是地址。
}
}
上面的输出为:
{"bear":{}}
{"bear":{}}
83954662
83954662
确实和期望一样,插入元素之后两者都发生了变化,且地址也是一样的,可见他们是指向相同的对象的。
但我们做以下的更改:
public class Test {
public static void main(String[] args) {
JSONObject jsonObject = new JSONObject();
Map<String, Object> data = new HashMap<String, Object>();
jsonObject.put("data", data);
ResponseObject t = new ResponseObject(jsonObject);
JSONObject bearObj = new JSONObject();
t.put("bear", bearObj);
System.out.println(t.getData());
System.out.println(t.data);
System.out.println(System.identityHashCode(t.getData()));
System.out.println(System.identityHashCode(t.data));
}
}
发现输出和期望的就有所不同了:
{}
{"bear":{}}
777874839
1751075886
原因很简单,通过观察 \(com.alibaba.fastjson.JSONObject\) 的代码
public JSONObject getJSONObject(String key) {
Object value = map.get(key);
if (value instanceof JSONObject) {
return (JSONObject) value;
}
if (value instanceof String) {
return JSON.parseObject((String) value);
}
return (JSONObject) toJSON(value);
}
发现这个方法在 \(data\) 不是 \(JSONObject\) 类时,会新建一个 \(JSONObject\) 然后再将元素插入进去,因此地址会发生改变,这种时候\(ResponseObject\)中的\(data\)与\(jsonObject\)中的\(data\)就不是同一个东西了。