【问题标题】:How do I clone an org.json.JSONObject in Java?如何在 Java 中克隆 org.json.JSONObject?
【发布时间】:2012-09-30 08:38:01
【问题描述】:

有没有办法克隆org.json.JSONObject 的实例而不对其进行字符串化并重新解析结果?

浅拷贝是可以接受的。

【问题讨论】:

  • 这个问题本身就是我的答案。 +1

标签: java json org.json


【解决方案1】:

我发现的最快+最少的方法是这样的。它做深拷贝。

JSONObject 克隆=新 JSONObject(original.toMap());

我知道提问者说

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

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

【讨论】:

    【解决方案2】:

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

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

    注意:这只是一个复制

    【讨论】:

      【解决方案3】:

      最简单(但极其缓慢且低效)的方法

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

      【讨论】:

      • 那将是对结果进行字符串化和解析,我说过我不想这样做。
      • 不过看起来是一种简单的深度克隆方法。
      • 该死我怎么没想到这个:P
      • 这种方式的问题是如果JSONObject有循环引用,调用toString()时会抛出StackOverflowError。
      • @codedabbler 如果你的 JSON 对象有循环引用,你可能需要重构一些东西
      【解决方案4】:

      导致$JSONObject.getNames(original)在android中无法访问, 你可以这样做:

      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;
      }
      

      但记住它不是深拷贝。

      【讨论】:

        【解决方案5】:

        如果有人来这里寻找 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;
        }
        

        【讨论】:

          【解决方案6】:

          找不到 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();
          }
          

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

          【讨论】:

            【解决方案7】:

            使用public JSONObject(JSONObject jo, java.lang.String[] names) 构造函数和public static java.lang.String[] getNames(JSONObject jo) 方法。

            JSONObject copy = new JSONObject(original, JSONObject.getNames(original));
            

            【讨论】:

            • 我想警告其他人,这种方法执行的是浅拷贝,提问者想要,但不要忘记它。
            • 警告:JSONObject.getNames(JSONObject instance) 在 Android 上不存在。
            猜你喜欢
            • 2017-09-17
            • 1970-01-01
            • 1970-01-01
            • 2014-04-19
            • 2010-09-08
            • 2011-11-14
            • 1970-01-01
            • 1970-01-01
            • 2017-03-26
            相关资源
            最近更新 更多