廢話少說,直接入題。
在面向對象語言中,經常會比較兩個對象是否相等,而比較的大多是實體類實例,也就是封裝數據的那些類實例,或者是Map、List互相嵌套成的復雜數據結構。
比較對象是否相等,常見的思路是重寫equals方法,但鑒於對象的種類多變,嵌套層次復雜,僅僅靠重寫equals是很難實現的。
小菜的思路是可以把對象序列化,由於這些對象均是用來表達數據結構,因此可以直接轉換成JSON字符串,用字符串來描述數據結構,避免實現Serializable接口。將對象序列化成字符串后,比較是否相等就相對簡單了。
小菜提供的正是比較兩個JSON串是否相等的方法,並不是說JSON串完全一樣才叫相等,對於List(或數組)結構而言,如果僅僅是元素排列順序不同,也是相等的。
為了保證方法的准確性,請傳入標准的JSON串,也就是說key也要加雙引號。用過js的童鞋可能會被誤導:我在js中寫的JSON,key可以不加雙引號啊!實際上,你在js中寫的是js語言的Object,並不是JSON,只不過它的語法和JSON非常像而已,JSON僅僅是一種字符串規范,而且真正的JSON只有一種,那就是key加了雙引號的!
另外,此方法不依賴任何第三方包。
最后聲明,由於數據結構復雜,小菜對這個方法不可能進行遍歷性測試,所以這個方法的准確性有待考究,請謹慎使用!如有問題,歡迎反饋!

1 import java.util.regex.Matcher; 2 import java.util.regex.Pattern; 3 4 /** 5 * 比較兩個json串是否相同 6 * @param j1 第一個json串(json串中不能有換行) 7 * @param j2 第二個json串(json串中不能有換行) 8 * @return 布爾型比較結果 9 */ 10 public static boolean jsonEquals(String j1,String j2){ 11 12 //將json中表示list的[]替換成{}。思想:只保留層次結構,不區分類型 13 //這樣直接替換,可能會導致某些value中的符號也被替換,但是不影響結果,因為j1、j2的變化是相對的 14 j1 = j1.replaceAll("\\[", "{"); 15 j1 = j1.replaceAll("]", "}"); 16 j2 = j2.replaceAll("\\[", "{"); 17 j2 = j2.replaceAll("]", "}"); 18 //將json中,字符串型的value中的{},字符替換掉,防止干擾(並沒有去除key中的,因為不可能存在那樣的變量名) 19 //未轉義regex:(?<=:")(([^"]*\{[^"]*)|([^"]*\}[^"]*)|([^"]*,[^"]*))(?=") 20 Pattern pattern = Pattern.compile("(?<=:\")(([^\"]*\\{[^\"]*)|([^\"]*\\}[^\"]*)|([^\"]*,[^\"]*))(?=\")"); 21 j1 = cleanStr4Special(j1, pattern.matcher(j1)); 22 j2 = cleanStr4Special(j2, pattern.matcher(j2)); 23 //轉義字符串value中的空格 24 //未轉義regex:"[^",]*?\s+?[^",]*?" 25 pattern = Pattern.compile("\"[^\",]*?\\s+?[^\",]*?\""); 26 j1 = cleanStr4Space(j1, pattern.matcher(j1)); 27 j2 = cleanStr4Space(j2, pattern.matcher(j2)); 28 //現在可以安全的全局性去掉空格 29 j1 = j1.replaceAll(" ", ""); 30 j2 = j2.replaceAll(" ", ""); 31 //調用遞歸方法 32 return compareAtom(j1,j2); 33 } 34 35 /** 36 * 比較字符串核心遞歸方法 37 * @param j1 38 * @param j2 39 * @return 40 */ 41 private static boolean compareAtom(String j1,String j2){ 42 43 if(!j1.equals("?:\"?\"")){ 44 //取出最深層原子 45 String a1 = j1.split("\\{",-1)[j1.split("\\{",-1).length-1].split("}",-1)[0]; 46 String a2 = j2.split("\\{",-1)[j2.split("\\{",-1).length-1].split("}",-1)[0]; 47 String j2_ = j2; 48 String a2_ = a2; 49 //轉換成原子項 50 String i1[] = a1.split(","); 51 //在同級原子中尋找相同的原子 52 while(!a2.startsWith(",") && 53 !a2.endsWith(",") && 54 a2.indexOf(":,")<0 && 55 a2.indexOf(",,")<0 56 ){ 57 //遍歷消除 58 for(String s : i1){ 59 a2_ = a2_.replace(s,""); 60 } 61 //此時a2_剩下的全是逗號,如果長度正好等於i1的長度-1,說明相等 62 if(a2_.length() == i1.length-1){ 63 //相等則從j1、j2中消除,消除不能簡單的替換,因為其他位置可能有相同的結構,必須從當前位置上消除 64 int index = 0; 65 index = j1.lastIndexOf("{" + a1 + "}"); 66 j1 = j1.substring(0, index)+j1.substring(index).replace("{" + a1 + "}", "?:\"?\""); 67 index = j2.lastIndexOf("{" + a2 + "}"); 68 j2 = j2.substring(0, index)+j2.substring(index).replace("{" + a2 + "}", "?:\"?\""); 69 //遞歸 70 return compareAtom(j1, j2); 71 }else{ 72 //尋找下一個同級原子 73 j2_ = j2_.replace("{" + a2 + "}", ""); 74 a2 = j2_.split("\\{",-1)[j2_.split("\\{",-1).length-1].split("}",-1)[0]; 75 a2_ = a2; 76 } 77 } 78 return false; 79 }else{ 80 //比較是否相同 81 return j1.equals(j2); 82 } 83 } 84 85 /** 86 * json字符串特殊字符清理輔助方法 87 * @param j 需要清理的json字符串 88 * @param matcher 正則表達式匹配對象 89 * @return 凈化的json串 90 */ 91 private static String cleanStr4Special(String j,Matcher matcher){ 92 String group = ""; 93 String groupNew = ""; 94 while(matcher.find()){ 95 group = matcher.group(); 96 groupNew = group.replaceAll("\\{", "A"); 97 groupNew = groupNew.replaceAll("}", "B"); 98 groupNew = groupNew.replaceAll(",", "C"); 99 j = j.replace(group, groupNew); 100 } 101 return j; 102 } 103 104 /** 105 * json串字符串類型的value中的空格清理輔助方法 106 * @param j 需要清理的json字符串 107 * @param matcher 正則表達式匹配對象 108 * @return 凈化的json串 109 */ 110 private static String cleanStr4Space(String j,Matcher matcher){ 111 String group = ""; 112 String groupNew = ""; 113 while(matcher.find()){ 114 group = matcher.group(); 115 groupNew = group.replaceAll(" ", "S"); 116 j = j.replace(group, groupNew); 117 } 118 return j; 119 }