之前遇到一些關於兩個引用類型是否指向同一個對象的問題,如下定義的\(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\)就不是同一個東西了。