如何在Java中克隆一个org.json.JSONObject对象?

52
有没有一种方法可以克隆一个 org.json.JSONObject 的实例而不需要将其转换为字符串并重新解析结果?
浅拷贝是可以接受的。

4
这个问题本身对我来说就是答案。+1 - lucidbrot
7个回答

92

最简单(但极其缓慢和低效)的方法是这样做

JSONObject clone = new JSONObject(original.toString());

3
那将会是将结果转化为字符串并解析,而我已经说过我不想这样做。 - Daniel Schaffer
22
看起来是深度克隆的简单方式。 - Jayen
3
该怎么办才好呢,我居然没想到这个方法:P - REJH
那么这似乎是执行深度克隆的唯一方法(使用JSONObject的公共API之一)? - helpermethod
1
这种方法的问题在于,如果JSONObject具有循环引用,当调用toString()时,它将抛出StackOverflowError。 - codedabbler
1
如果您的JSON对象具有循环引用,那么您可能需要重构一些内容。 - Jonathan E. Landrum

64

35
我想提醒其他人,这种方法执行的是浅复制,提问者想要这样做,但不要忘记这一点。 - satur9nine
8
警告:JSONObject.getNames(JSONObject instance) 在Android上不存在。 - icodestuff

4

我发现最快速、最简单的方法是这个,它可以进行深度复制。

JSONObject clone = new JSONObject(original.toMap());

我知道提问者说:

浅拷贝也可以接受。 但我认为这并不排除解决方案会进行深度复制。

更新:toMap() 函数在 Android 中不可用。但是,在 Maven 上有可用的 org.json 库,位于 groupId org.json 下:https://search.maven.org/artifact/org.json/json/20210307/bundle


3

对于Android开发者而言,不使用.getNames的最简单解决方案是:

JSONObject copy = new JSONObject();
for (Object key : original.keySet()) {
  Object value = original.get(key);
  copy.put(key, value);
}

注意:这只是一个浅复制

3

由于在Android中无法访问$JSONObject.getNames(original),您可以使用以下方法:

public JSONObject shallowCopy(JSONObject original) {
    JSONObject copy = new JSONObject();

    for ( Iterator<String> iterator = original.keys(); iterator.hasNext(); ) {
        String      key     = iterator.next();
        JSONObject  value   = original.optJSONObject(key);

        try {
            copy.put(key, value);
        } catch ( JSONException e ) {
            //TODO process exception
        }
    }

    return copy;
}

但请记住,这不是深拷贝。


2

无法找到现有的深层克隆方法来克隆com.google.gwt.json.client.JSONObject,但其实现应该只需几行代码,类似于:

public static JSONValue deepClone(JSONValue jsonValue){
    JSONString string = jsonValue.isString();
    if (string != null){return new JSONString(string.stringValue());}

    JSONBoolean aBoolean = jsonValue.isBoolean();
    if (aBoolean != null){return JSONBoolean.getInstance(aBoolean.booleanValue());}

    JSONNull aNull = jsonValue.isNull();
    if (aNull != null){return JSONNull.getInstance();}

    JSONNumber number = jsonValue.isNumber();
    if (number!=null){return new JSONNumber(number.doubleValue());}

    JSONObject jsonObject = jsonValue.isObject();
    if (jsonObject!=null){
        JSONObject clonedObject = new JSONObject();
        for (String key : jsonObject.keySet()){
            clonedObject.put(key, deepClone(jsonObject.get(key)));
        }
        return clonedObject;
    }

    JSONArray array = jsonValue.isArray();
    if (array != null){
        JSONArray clonedArray = new JSONArray();
        for (int i=0 ; i < array.size() ; ++i){
            clonedArray.set(i, deepClone(array.get(i)));
        }
        return clonedArray;
    }

    throw new IllegalStateException();
}

注意:我还没有测试过它!


-2

如果有人在这里寻找org.google.gson的深度克隆方法,因为他们没有公开他们的deepClone()方法,这是我想出来的...

public static JsonElement deepClone(JsonElement el){
    if (el.isJsonPrimitive() || el.isJsonNull())
        return el;
    if (el.isJsonArray()) {
        JsonArray array = new JsonArray();
        for(JsonElement arrayEl: el.getAsJsonArray())
            array.add(deepClone(arrayEl));
        return array;
    }
    if(el.isJsonObject()) {
        JsonObject obj = new JsonObject();
        for (Map.Entry<String, JsonElement> entry : el.getAsJsonObject().entrySet()) {
            obj.add(entry.getKey(), deepClone(entry.getValue()));
        }
        return obj;
    }
    throw new IllegalArgumentException("JsonElement type " + el.getClass().getName());
}

以下是合并两个JsonObject的几种方法

public static JsonObject merge(String overrideJson, JsonObject defaultObj) {
    return mergeInto((JsonObject)new JsonParser().parse(overrideJson), defaultObj);
}
public static JsonObject merge(JsonObject overrideObj, JsonObject defaultObj) {
    return mergeOverride((JsonObject)deepClone(defaultObj), overrideObj);
}
public static JsonObject mergeOverride(JsonObject targetObj, JsonObject overrideObj) {
    for (Map.Entry<String, JsonElement> entry : overrideObj.entrySet())
            targetObj.add(entry.getKey(), deepClone(entry.getValue()));
    return targetObj;
}
public static JsonObject mergeInto(JsonObject targetObj, JsonObject defaultObj) {
    for (Map.Entry<String, JsonElement> entry : defaultObj.entrySet()) {
        if (targetObj.has(entry.getKey()) == false)
            targetObj.add(entry.getKey(), deepClone(entry.getValue()));
    }
    return targetObj;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接