JAVA如何判断两个json对象等价

在做软件和网络测试的时候,经常需要对格式与结构不固定的json对象进行对比,而json基本语法下,同样的一个json对象,字符串变化可以千变万化,json内各个层字段顺序调转,排版变化,打乱顺序的json数组+多层嵌套,等等各种因素,都会造成对比上的困难。

以下由浅及深谈谈几种方法: (一共五种方法,四和五是无缺陷方法,把问题转变成判断两个多叉树是否等价,解决思路将多叉树按照哈希排序把父节点相同的子节点从左到右重排)

一.字符串对比,外加正则方式对比 ,因为json字符串可变化方式太多,出错率过高略过不谈。

二.转为json对象后对比,可通过几个常用的json库将json字符串转换成对象,这时候可以完全排除掉空格和换行等等纯排版原因造成的差异.

转换为json对象后可以递归取出所有键值对,然后通过遍历map对比,缺陷是当存在同名字段的时候会出现问题

以com.google.gson包为例,遍历字段存入map,再对比map是否一致

三. 转为json对象后,判断内部顺序差异,net.sf.json包可以直接使用 JSONObject.hashCode()对比,com.google.gson包与 vertx.core.json 包无法使用该方法,顺序稍加变化就会对比错误。

net.sf.json包构造json对象并对比

简单例子:

json数组对象a=[{"firstName":"John","lastName":"Doe"},
                      {"firstName":"Peter","lastName":"Jones"},
                      {"firstName":"Anna","lastName":"Smith"}
json数组对象b=[
                    {"firstName":"Peter","lastName":"Jones"},
                    {"firstName":"Anna","lastName":"Smith"},
                    {"firstName":"John","lastName":"Doe"}
                      ]

肉眼观察可知其中只有顺序调整了,字段和对应的值是没有改变的,二者应该等价。

net.sf.json包通过对比哈希码的方式可以得出两个json对象等价,而com.google.gson包与 vertx.core.json 包均不能正确判断。


稍微复杂例子(存在两层数组嵌套,内部元素顺序也加了变化):

json对象a={
"obj_1": "name",
"field_1": "11",
"list_1": [
       "obj_2.1": "obj_2.1",
       "field_2.1": "21"
       "obj_2.2": "obj_2.2",
       "field_2.2": "22"
       "obj_2.3.1": "obj_2.3.1",
       "field_2.3.1": "231"
       "obj_2.3.2": "obj_2.3.2",
       "field_2.3.2": "232"
json对象b={
"field_1": "11",
"obj_1": "name",
"list_1": [
		    "field_2.2": "22",
              "obj_2.2": "obj_2.2"
       "obj_2.3.1": "obj_2.3.1",
       "field_2.3.1": "231"
       "obj_2.3.2": "obj_2.3.2",
       "field_2.3.2": "232"
       "field_2.1": "21",
	    "obj_2.1": "obj_2.1"
}

net.sf.json包对于这两个较为复杂的等价json对象依然能正确判断出来。


本来到这里,用net.sf.json包已经可以一步到位判断两个json是否等价了,但是后来发现这个包构造的json对象有个缺陷,就是hashCode方法无法区分 Integer和String类型

如:{

"id": "123"

}

{

"id": 123

}

net.sf.json包构造的两个对象的hashCode等价(当然toString方法是能判断出差异的),明显二者字段类型不同

附录测试代码,可直接运行:

package test;
import net.sf.json.*;
// net.sf.json包实现
//Integer型和String型判断错误
public class JsonContrast_3 {
   static void contrast(Object a,Object b){         //将jsonObject或JsonArray的内部元素按照规则重新排序
      boolean i = false;
      System.out.println("json对象a="+a.toString());
      System.out.println("json对象b="+b.toString());
      if(a.hashCode()==b.hashCode()){
         i=true;
      System.out.println("两个json对象是否等价:"+i);
   public static void main(String[] args){
      String a= "[\n" +
            "{ \"firstName\":\"John\" , \"lastName\":\"Doe\" },\n" +
            "{ \"firstName\":\"Peter\" , \"lastName\":\"Jones\" },\n" +
            "{ \"firstName\":\"Anna\" , \"lastName\":\"Smith\" }\n" +
            "\n" +
            "]\n";
      String b="[\n" +
            "{ \"firstName\":\"Peter\" , \"lastName\":\"Jones\" },\n" +
            "{ \"firstName\":\"Anna\" , \"lastName\":\"Smith\" },\n" +
            "{ \"firstName\":\"John\" , \"lastName\":\"Doe\" }\n" +
            "\n" +
            "]\n";
      JSONArray js1= JSONArray.fromObject(a);
      JSONArray js2= JSONArray.fromObject(b);
      contrast(js1,js2);
      //net.sf.json包会认为 "field": abc123 非法,而com.google.gson包会自行转成 "field": "abc123"
      a= "{\n" +
            "    \"obj_1\": \"name\",\n" +
            "    \"field_1\": \"11\",\n" +
            "    \"list_1\": [\n" +
            "        {\n" +
            "            \"obj_2.1\": \"obj_2.1\",\n" +
            "            \"field_2.1\": \"21\"\n" +
            "        },\n" +
            "        {\n" +
            "            \"obj_2.2\": \"obj_2.2\",\n" +
            "            \"field_2.2\": \"22\"\n" +
            "        },\n" +
            "\t\t[ \n" +
            "\t\t{\n" +
            "            \"obj_2.3.1\": \"obj_2.3.1\",\n" +
            "            \"field_2.3.1\": \"231\"\n" +
            "        },\n" +
            "        {\n" +
            "            \"obj_2.3.2\": \"obj_2.3.2\",\n" +
            "            \"field_2.3.2\": \"232\"\n" +
            "        }\n" +
            "\t\t\n" +
            "\t\t]\n" +
            "    ]\n" +
      b="{\n" +
            "    \"field_1\": \"11\",\n" +
            "    \"obj_1\": \"name\",\n" +
            "    \"list_1\": [\n" +
            "        \n" +
            "        {\n" +
            "\t\t    \"field_2.2\": \"22\",\n" +
            "            \"obj_2.2\": \"obj_2.2\"\n" +
            "        },\n" +
            "\t\t\n" +
            "\t\t[ \n" +
            "\t\t{\n" +
            "            \"obj_2.3.1\": \"obj_2.3.1\",\n" +
            "            \"field_2.3.1\": \"231\"\n" +
            "        },\n" +
            "        {\n" +
            "            \"obj_2.3.2\": \"obj_2.3.2\",\n" +
            "            \"field_2.3.2\": \"232\"\n" +
            "        }\n" +
            "\t\t],\n" +
            "\t\t\n" +
            "\t\t{\n" +
            "            \"field_2.1\": \"21\",\n" +
            "\t\t\t\"obj_2.1\": \"obj_2.1\"\n" +
            "            \n" +
            "        }\n" +
            "    ]\n" +
        JSONObject jsA= JSONObject.fromObject(a);
      JSONObject jsB= JSONObject.fromObject(b);
      System.out.println(jsA.hashCode()==jsB.hashCode());
      contrast(jsA,jsB);



以上几种方式都存在局限性,以下四和五是完全正确匹配方式,


. 通过调整net.sf.json包构造的json对象的顺序,并最终形成统一的json字符串(也就N个等价的json对象,都可以生成唯一标准的json字符串)

由于net.sf.json包在(三)里的hashCode等价特性,所以子节点的顺序变化是不会影响父节点的hashCode的,因而可以通过自上而下递归调整处于同一层字段的相互顺序,按照hashCode大小排序的方式,自上而下对整个json对象重新排序.

//自上而下将json对象的各个元素重新排序,采用将json对象排序后重新组装的方式
static void arrangeJson(Object js){
   if(js instanceof JSONObject){
      JSONObject jsCopy =    JSONObject.fromObject(js.toString());    //将json对象复制一份,进行递归遍历取值
      Iterator i=jsCopy.entrySet().iterator();
      ArrayList<Object> arr=new ArrayList<Object>();
      while(i.hasNext()){
         Map.Entry entry = (Map.Entry)i.next();
         arr.add(entry.getKey().toString());           //逐个取出子节点对象
         //System.out.println(entry.getKey() + "    " + entry.getValue()+" "+jsCopy.get(entry.getKey()).getClass());
         ((JSONObject)js).remove(entry.getKey().toString());         //清空旧的子元素
      sortArr(arr);
      for(int n=0;n<arr.size();n++){
         //System.out.println("arr="+arr.get(n));
         String key=arr.get(n).toString();
         if(jsCopy.get(key) instanceof JSONObject||(jsCopy.get(key) instanceof JSONArray)){
            arrangeJson(jsCopy.get(key));         //递归调整json对象
         ((JSONObject)js).put(key,jsCopy.get(key));               //重新组装序列化的子元素
   if(js instanceof JSONArray) {
      JSONArray jsCopy=JSONArray.fromObject(js.toString());
      ArrayList<Object> arr=new ArrayList<Object>();
      for(int n=0;n<jsCopy.size();n++){
         arr.add(jsCopy.get(n));
         ((JSONArray) js).remove(0);
      sortArr(arr);
      for(int n=0;n<arr.size();n++){
         //System.out.println("arr_"+n+arr.get(n));
         arrangeJson((Object)arr.get(n));
         ((JSONArray) js).add((Object)arr.get(n));
//将数组元素按照哈希码从小到大重新排序
private static void sortArr(ArrayList<Object> arr){
   int len=arr.size();
   int[] n=new int[len];
   ArrayList<Object> arrCopy=(ArrayList<Object>)arr.clone();
   Object[] obj=new Object[len];
   for(int i=0;i<len;i++){
      n[i]=arrCopy.get(i).hashCode();
      obj[i]=arrCopy.get(i);
      arr.remove(0);
   for(int i=0;i<len;i++){
      for(int y=i+1;y<len;y++){
         if(n[i]<n[y]){
            int x=n[y];
            n[y]=n[i];
            n[i]=x;
            Object s=obj[y];
            obj[y]=obj[i];
            obj[i]=s;
   for(int i=0;i<len;i++){
      arr.add(obj[i]);
}


最后通过 jsA.toString().equals(jsB.toString()) 方法判断,通过这样的方式可以避免(三)中无法区分 Integer和String的缺陷

附录测试代码,可直接运行:

package test;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
//net.sf.json包实现
public class JsonContrast_1 {
    public static void main(String[] args) {
      String a= "[\n" +
            "            {\n" +
            "                \"title\": \"Happy Day\",\n" +
            "                \"url\": \"URL\",\n" +
            "                \"picurl\": \"PIC_URL26787z\",\n" +
            "                \"description\": \"Is Really A Happy Day\"\n" +
            "            },\n" +
            "          \n" +
            "            {\n" +
            "                \"object\": {\n" +
            "                    \"name2\": \"name2\",\n" +
            "                    \"list1\": [\n" +
            "                        {\n" +
            "                            \"title\": \"Happy Day\",\n" +
            "                            \"url\": \"URL\",\n" +
            "                            \"picurl111\": \"PIC_URL333\",\n" +
            "                            \"description\": \"Is Really A Happy Day\"\n" +
            "                        },\n" +
            "                        {\n" +
            "                            \"title\": \"Happy Day\",\n" +
            "                            \"url\": \"URL\",\n" +
            "                            \"picurl222\": \"PIC_URL444\",\n" +
            "                            \"description\": \"Is Really A Happy Day\"\n" +
            "                        },\n" +
            "                        {\n" +
            "                            \"title\": \"title\",\n" +
            "                            \"url\": \"URL\",\n" +
            "                            \"picurl222\": \"PIC_URL444\",\n" +
            "                            \"description\": \"description\"\n" +
            "                        }\n" +
            "                    ],\n" +
            "                    \"list2\": [\n" +
            "\t\t\t\t\t{\"test5\":\"5555\"},\n" +
            "\t\t\t\t\t{\"test3\":\"333\"},\n" +
            "\t\t\t\t\t{\"test2\":\"222\"},\n" +
            "\t\t\t\t\t\t\n" +
            "\t\t\t\t\t\t{\"test4\":\"4444\"}\n" +
            "\t\t\t\t\t\t\n" +
            "                    ],\n" +
            "                    \"name1\": \"name1\"\n" +
            "                }\n" +
            "            },\n" +
            "\t\t\t  {\n" +
            "                \"title\": \"Happy Day\",\n" +
            "                \"url\": \"URL\",\n" +
            "                \"picurl\": \"PIC_URL111\",\n" +
            "                \"description\": \"Is Really A Happy Day\"\n" +
            "            }\n" +
            "        ]";
      String b="[\n" +
            "            {\n" +
            "                \"title\": \"Happy Day\",\n" +
            "                \"url\": \"URL\",\n" +
            "                \"picurl\": \"PIC_URL111\",\n" +
            "                \"description\": \"Is Really A Happy Day\"\n" +
            "            },\n" +
            "            {\n" +
            "                \"title\": \"Happy Day\",\n" +
            "                \"url\": \"URL\",\n" +
            "                \"picurl\": \"PIC_URL26787z\",\n" +
            "                \"description\": \"Is Really A Happy Day\"\n" +
            "            },\n" +
            "            {\n" +
            "                \"object\": {\n" +
            "                    \"name1\": \"name1\",\n" +
            "                    \n" +
            "                    \"list2\": [\n" +
            "                        {\"test2\":\"222\"},\n" +
            "\t\t\t\t\t\t{\"test3\":\"333\"},\n" +
            "\t\t\t\t\t\t{\"test4\":\"4444\"},\n" +
            "\t\t\t\t\t\t{\"test5\":\"5555\"}\n" +
            "                            \n" +
            "                    ],\n" +
            "\t\t\t\t\t\"list1\": [\n" +
            "                        {\n" +
            "                            \"title\": \"Happy Day\",\n" +
            "                            \"url\": \"URL\",\n" +
            "                            \"picurl111\": \"PIC_URL333\",\n" +
            "                            \"description\": \"Is Really A Happy Day\"\n" +
            "                        },\n" +
            "                        {\n" +
            "                            \"title\": \"Happy Day\",\n" +
            "                            \"url\": \"URL\",\n" +
            "                            \"picurl222\": \"PIC_URL444\",\n" +
            "                            \"description\": \"Is Really A Happy Day\"\n" +
            "                        },\n" +
            "                        {\n" +
            "                            \"title\": \"title\",\n" +
            "                            \"url\": \"URL\",\n" +
            "                            \"picurl222\": \"PIC_URL444\",\n" +
            "                            \"description\": \"description\"\n" +
            "                        }\n" +
            "                    ],\n" +
            "                    \"name2\": \"name2\"\n" +
            "                }\n" +
            "            }\n" +
            "        ]";
      JSONArray js1= JSONArray.fromObject(a);
      JSONArray js2= JSONArray.fromObject(b);
        arrangeJson(js1);
      arrangeJson(js2);
      contrast(js1,js2);
      //net.sf.json包会认为 "field": abc123 非法,而com.google.gson包会自行转成 "field": "abc123"
      a= "{\n" +
            "    \"msgtype\": \"1234\",\n" +
            "    \"news\": {\n" +
            "        \"articles\": [\n" +
            "            {\n" +
            "                \"title\": \"Happy Day\",\n" +
            "                \"url\": \"URL\",\n" +
            "                \"picurl\": \"PIC_URL26787z\",\n" +
            "                \"description\": \"Is Really A Happy Day\"\n" +
            "            },\n" +
            "          \n" +
            "            {\n" +
            "                \"object\": {\n" +
            "                    \"name2\": \"name2\",\n" +
            "                    \"list1\": [\n" +
            "                        {\n" +
            "                            \"title\": \"Happy Day\",\n" +
            "                            \"url\": \"URL\",\n" +
            "                            \"picurl111\": \"PIC_URL333\",\n" +
            "                            \"description\": \"Is Really A Happy Day\"\n" +
            "                        },\n" +
            "                        {\n" +
            "                            \"title\": \"Happy Day\",\n" +
            "                            \"url\": \"URL\",\n" +
            "                            \"picurl222\": \"PIC_URL444\",\n" +
            "                            \"description\": \"Is Really A Happy Day\"\n" +
            "                        },\n" +
            "                        {\n" +
            "                            \"title\": \"title\",\n" +
            "                            \"url\": \"URL\",\n" +
            "                            \"picurl222\": \"PIC_URL444\",\n" +
            "                            \"description\": \"description\"\n" +
            "                        }\n" +
            "                    ],\n" +
            "                    \"list2\": [\n" +
            "\t\t\t\t\t{\"test5\":\"5555\"},\n" +
            "\t\t\t\t\t{\"test3\":\"333\"},\n" +
            "\t\t\t\t\t{\"test2\":\"222\"},\n" +
            "\t\t\t\t\t\t\n" +
            "\t\t\t\t\t\t{\"test4\":\"4444\"}\n" +
            "\t\t\t\t\t\t\n" +
            "                    ],\n" +
            "                    \"name1\": \"name1\"\n" +
            "                }\n" +
            "            },\n" +
            "\t\t\t  {\n" +
            "                \"title\": \"Happy Day\",\n" +
            "                \"url\": \"URL\",\n" +
            "                \"picurl\": \"PIC_URL111\",\n" +
            "                \"description\": \"Is Really A Happy Day\"\n" +
            "            }\n" +
            "        ]\n" +
            "    },\n" +
            "    \"touser\": \"OPENID\"\n" +
      b="{\"touser\": \"OPENID\",\n" +
            "    \"msgtype\": \"1234\",\n" +
            "    \"news\": {\n" +
            "        \"articles\": [\n" +
            "            {\n" +
            "                \"title\": \"Happy Day\",\n" +
            "                \"url\": \"URL\",\n" +
            "                \"picurl\": \"PIC_URL111\",\n" +
            "                \"description\": \"Is Really A Happy Day\"\n" +
            "            },\n" +
            "            {\n" +
            "                \"title\": \"Happy Day\",\n" +
            "                \"picurl\": \"PIC_URL26787z\",\n" +
            "                \"url\": \"URL\",\n" +
            "                \"description\": \"Is Really A Happy Day\"\n" +
            "            },\n" +
            "            {\n" +
            "                \"object\": {\n" +
            "                    \"name1\": \"name1\",\n" +
            "                    \n" +
            "                    \"list2\": [\n" +
            "                        {\"test2\":\"222\"},\n" +
            "\t\t\t\t\t\t{\"test3\":\"333\"},\n" +
            "\t\t\t\t\t\t{\"test4\":\"4444\"},\n" +
            "\t\t\t\t\t\t{\"test5\":\"5555\"}\n" +
            "                            \n" +
            "                    ],\n" +
            "\t\t\t\t\t\"list1\": [\n" +
            "                        {\n" +
            "                            \"title\": \"Happy Day\",\n" +
            "                            \"url\": \"URL\",\n" +
            "                            \"picurl111\": \"PIC_URL333\",\n" +
            "                            \"description\": \"Is Really A Happy Day\"\n" +
            "                        },\n" +
            "                        {\n" +
            "                            \"title\": \"Happy Day\",\n" +
            "                            \"url\": \"URL\",\n" +
            "                            \"picurl222\": \"PIC_URL444\",\n" +
            "                            \"description\": \"Is Really A Happy Day\"\n" +
            "                        },\n" +
            "                        {\n" +
            "                            \"title\": \"title\",\n" +
            "                            \"url\": \"URL\",\n" +
            "                            \"picurl222\": \"PIC_URL444\",\n" +
            "                            \"description\": \"description\"\n" +
            "                        }\n" +
            "                    ],\n" +
            "                    \"name2\": \"name2\"\n" +
            "                }\n" +
            "            }\n" +
            "        ]\n" +
            "    }\n" +
            "    \n" +
      JSONObject js3= JSONObject.fromObject(a);
      JSONObject js4= JSONObject.fromObject(b);
      arrangeJson(js3);
      arrangeJson(js4);
      contrast(js3,js4);
   static void contrast(Object a,Object b){
      boolean i = false;
      System.out.println("json对象a序列化="+a.toString());
      System.out.println("json对象b序列化="+b.toString());
      if(a.toString().equals(b.toString())){
         i=true;
      System.out.println("两个json对象是否等价:"+i);
   //将json对象的各个元素重新排序
   static void arrangeJson(Object js){
      if(js instanceof JSONObject){
         JSONObject jsCopy =    JSONObject.fromObject(js.toString());    //将json对象复制一份,进行递归遍历取值
         Iterator i=jsCopy.entrySet().iterator();
         ArrayList<Object> arr=new ArrayList<Object>();
         while(i.hasNext()){
            Map.Entry entry = (Map.Entry)i.next();
            arr.add(entry.getKey().toString());
            //System.out.println(entry.getKey() + "    " + entry.getValue()+" "+jsCopy.get(entry.getKey()).getClass());
            ((JSONObject)js).remove(entry.getKey().toString());         //清空旧的子元素
         sortArr(arr);
         for(int n=0;n<arr.size();n++){
            //System.out.println("arr="+arr.get(n));
            String key=arr.get(n).toString();
            if(jsCopy.get(key) instanceof JSONObject||(jsCopy.get(key) instanceof JSONArray)){
               arrangeJson(jsCopy.get(key));         //递归调整json对象
            ((JSONObject)js).put(key,jsCopy.get(key));               //重新组装序列化的子元素
      if(js instanceof JSONArray) {
         JSONArray jsCopy=JSONArray.fromObject(js.toString());
         ArrayList<Object> arr=new ArrayList<Object>();
         for(int n=0;n<jsCopy.size();n++){
            arr.add(jsCopy.get(n));
            ((JSONArray) js).remove(0);
         sortArr(arr);
         for(int n=0;n<arr.size();n++){
            //System.out.println("arr_"+n+arr.get(n));
            arrangeJson((Object)arr.get(n));
            ((JSONArray) js).add((Object)arr.get(n));
   //将数组元素按照哈希码从小到大重新排序
   private static void sortArr(ArrayList<Object> arr){
      int len=arr.size();
      int[] n=new int[len];
      ArrayList<Object> arrCopy=(ArrayList<Object>)arr.clone();
      Object[] obj=new Object[len];
      for(int i=0;i<len;i++){
         n[i]=arrCopy.get(i).hashCode();
         obj[i]=arrCopy.get(i);
         arr.remove(0);
      for(int i=0;i<len;i++){
         for(int y=i+1;y<len;y++){
            if(n[i]<n[y]){
               int x=n[y];
               n[y]=n[i];
               n[i]=x;
               Object s=obj[y];
               obj[y]=obj[i];
               obj[i]=s;
      for(int i=0;i<len;i++){
         arr.add(obj[i]);

五.不使用net.sf.json包,需要通过构造多叉树的方式,自下而上调整树节点的左右顺序的方式来让等价的json对象内部顺序唯一化.

以com.google.gson包为例:

链表对象:

public static class jsonObj{                               //多叉树双向链表对象
   int fatherId=-1;                                       //父节点的ID
   ArrayList<Integer> sonId=new ArrayList<Integer>();     //子节点ID数组
   ArrayList<Object> sonKey=new ArrayList<Object>();      //子节点键值,当前存放的对象为JsonArray时为空
   Object obj;                                            //当前存放的对象
   boolean isSort;                                        //当前对象是否已经完成排序
}

getArrangeJson方法为获取排序后的json对象,内部通过setObjArr(js,jsonObjs)方法将初始json对象转换成多叉树链表,通过arrangeArr(jsonObjs)自下而上调整多叉树链表的顺序结构,最终将多叉树链表还原成内部排序完成的json对象。

static Object getArrangeJson(Object js){
      ArrayList<jsonObj> jsonObjs = new ArrayList<jsonObj>(); //声明链表对象
      setObjArr(js,jsonObjs);                                //将json对象自上而下转换成链表对象
      arrangeArr(jsonObjs);                                  //将链表对象自下而上调整顺序
      return jsonObjs.get(0).obj;
   static void arrangeArr(ArrayList<jsonObj> jsonObjs) {
      int len = jsonObjs.size();
      boolean[] isSort = new boolean[len];
      boolean isAllSort = false;
      while (!isAllSort) {
         //判断是否全部完成排序
         for (int i = 0; i < len; i++) {
            isAllSort = isSort[i];
            if (!isAllSort)
               break;
         for (int n = 0; n < len; n++) {
                  int fatherId = jsonObjs.get(n).fatherId;
              if (fatherId != -1 && is_End_or_Sort(jsonObjs, n, fatherId)) {
                  jsonObj fatherObj = jsonObjs.get(fatherId);
                  ArrayList<Integer> sonId = fatherObj.sonId;
                  if (fatherObj.obj instanceof JsonObject) {
                     sortArr(fatherObj.sonKey, fatherObj.sonId);
                     JsonObject obj = new JsonObject();
                     for (int m = 0; m < fatherObj.sonId.size(); m++) {
                        obj.add(fatherObj.sonKey.get(m).toString(), (JsonElement) jsonObjs.get(fatherObj.sonId.get(m)).obj);
                        jsonObjs.get(fatherObj.sonId.get(m)).isSort = true;
                        isSort[fatherObj.sonId.get(m)] = true;
                     fatherObj.obj = obj;
                     fatherObj.isSort = true;
                     isSort[fatherId] = true;
                  if (fatherObj.obj instanceof JsonArray) {
                     ArrayList<Object> list = new ArrayList<Object>();
                     for (int m = 0; m < ((JsonArray) fatherObj.obj).size(); m++) {
                        list.add(((JsonArray) fatherObj.obj).get(m));
                     sortArr(list, fatherObj.sonId);
                     JsonArray obj = new JsonArray();
                     for (int m = 0; m < fatherObj.sonId.size(); m++) {
                        obj.add((JsonElement) jsonObjs.get(fatherObj.sonId.get(m)).obj);
                        jsonObjs.get(fatherObj.sonId.get(m)).isSort = true;
                        isSort[fatherObj.sonId.get(m)] = true;
                     fatherObj.obj = obj;
                     fatherObj.isSort = true;
                     isSort[fatherId] = true;
   static boolean is_End_or_Sort(ArrayList<jsonObj> jsonObjs,int id,int fatherId){
      boolean b=true;
      ArrayList<Integer> sonId= jsonObjs.get(fatherId).sonId;
      for(int n=0;n<sonId.size();n++){
           if(!(jsonObjs.get(sonId.get(n)).obj instanceof com.google.gson.JsonPrimitive) && !jsonObjs.get(sonId.get(n)).isSort){
                b=false;
                break;
        return b;
   static void contrast(Object a,Object b){         //将jsonObject或JsonArray的内部元素按照规则重新排序
      boolean i = false;
      System.out.println("json对象a序列化="+a.toString());
      System.out.println("json对象b序列化="+b.toString());
//    if(a.hashCode()==b.hashCode()){              //hashCode与toString两种比较方法均可
//       i=true;
//    }
      if(a.toString().equals(b.toString())){
         i=true;
      System.out.println("两个json对象是否等价:"+i);
   //将json对象自上而下逐个分解转换成链表对象
   static void setObjArr(Object js,ArrayList<jsonObj> jsonObjs){
      jsonObj obj;
      if(jsonObjs.size()==0) {
         obj = new jsonObj();
         obj.obj=js;
         jsonObjs.add(obj);
      else{
         obj=jsonObjs.get(jsonObjs.size()-1);
      int id=jsonObjs.size()-1;
      if(js instanceof  JsonObject) {
         Iterator i$ = ((JsonObject) js).entrySet().iterator();    //递归遍历子元素
         //ArrayList<>
         while (i$.hasNext()) {
            Map.Entry entry = (Map.Entry) i$.next();
            jsonObj sonObj = new jsonObj();
            sonObj.fatherId=id;
            sonObj.obj=entry.getValue();
            obj.sonId.add(jsonObjs.size());
            jsonObjs.add(sonObj);
                obj.sonKey.add(entry.getKey().toString());
               if (!(entry.getValue() instanceof com.google.gson.JsonPrimitive)) {
               setObjArr(entry.getValue(),jsonObjs);    //自上而下递归
      if(js instanceof  JsonArray){
         for(int n=0;n<((JsonArray) js).size();n++){
            jsonObj sonObj = new jsonObj();
            sonObj.fatherId=id;
            sonObj.obj=((JsonArray) js).get(n);
            obj.sonId.add(jsonObjs.size());
            jsonObjs.add(sonObj);
            setObjArr(((JsonArray) js).get(n),jsonObjs);   //自上而下递归
   //将数组元素按照哈希码从小到大重新排序
   private static boolean sortArr(ArrayList<Object> arr, ArrayList<Integer> idArr){
      boolean b=false;
      int len=arr.size();
      int[] n=new int[len];
      for(int i=0;i<len;i++){
         n[i]=arr.get(i).toString().hashCode();
      for(int i=0;i<len;i++){
         for(int y=i+1;y<len;y++){
            if(n[i]<n[y]){
               int x=n[y];
               n[y]=n[i];
               n[i]=x;
               Object s=arr.get(y);
               arr.set(y,arr.get(i));
               arr.set(i,s);
               x = idArr.get(y);
               idArr.set(y,idArr.get(i));
               idArr.set(i,x);