org.json.JSONObject相信不少人都用過,例如:服務端返回給客戶端的數據格式是JSONObject的,那咱們經過對它進行解析,把它顯示在界面上。html
有時候但願服務器跟客戶端通訊的JSONObjectt的鍵值對順序是固定的。json
例如:數組
客戶端提交一個JSONObject格式的數據,裏面有三個鍵值對,分別是"a":"a" "b":"b" "c":"c"服務器
服務端原封不動返回給客戶端,這個客戶端但願接到的是這樣的app
{"a":"a","b":"b","c":"c"}ide
但JSONObject的鍵值對順序幾乎不能肯定的,無規律可循,驗證以下:this
1. <pre name="code" class="html"> code
JSONObject object=new JSONObject();
try {
object.putOpt("b", "b");
object.putOpt("a", "a");
object.putOpt("c", "c");
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}htm
object.toString(),獲得的是rem
{"b":"b","c":"c","a":"a"}
與put進去時候的順序不一致。
2.
JSONObject object=new JSONObject();
try {
object.putOpt("1", "1");
object.putOpt("2", "2");
object.putOpt("3", "3");
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
object.toString(),獲得的是
{"3":"3","2":"2","1":"1"}
與put進去時候的順序不一致
3.
JSONObject object=new JSONObject();
try {
object.putOpt("我", "我");
object.putOpt("你", "你");
object.putOpt("他", "他");
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
object.toString(),獲得的是
{"你":"你","他":"他","我":"我"}
與put進去時候的順序不一致。
以上三個例子,不管鍵和值是數字、字母仍是中文,JSONObject put進去的順序喝toString獲得的順序,是不一致的。
若是還有疑問,咱們看看JSONObject的源碼吧。
先看構造方法:
public JSONObject() {
nameValuePairs = new HashMap<String, Object>();
}
再看putOpt 以及put方法:
public JSONObject putOpt(String name, Object value) throws JSONException {
if (name == null || value == null) {
return this;
}
return put(name, value);
}
public JSONObject put(String name, Object value) throws JSONException {
if (value == null) {
nameValuePairs.remove(name);
return this;
}
if (value instanceof Number) {
// deviate from the original by checking all Numbers, not just floats & doubles
JSON.checkDouble(((Number) value).doubleValue());
}
nameValuePairs.put(checkName(name), value);
return this;
}
這下可明白了吧,其實JSONObject本質是用HashMap實現的,而HashMap是散列的,是鏈式存儲結構。
HashMap的存儲過程,根據該元素自身提供的hashcode計算出散列值(在這一點上,就能夠知道,元素放進去的位置是沒法肯定的,只有在獲取hashcode後才知道),該值就是數組的下標,而後將該元素放入數組位置的鏈表中。
那麼如何固定它的順序呢,put進去是咱們想要的呢?有兩個方法:自定義JSONObject(不用HashMap改用LinkHashMap實現)或使用com.alibaba.fastjson.annotation.JSONType標註
1.自定義JSONObject(不用HashMap改用LinkHashMap實現),LinkedHashMap是有序的,代替無序的HashMap,把父類用到HashMap的地方都改爲LinkedHashMap便可,主要是put跟toString的幾個方法。
public class MyJSONObject extends JSONObject {
private LinkedHashMap<Object, Object> mHashMap;
public ChatMsgJSONObject() {
mHashMap = new LinkedHashMap<Object, Object>();
}
@Override
public JSONObject put(String name, boolean value) throws JSONException {
// TODO Auto-generated method stub
return put(name, value);
}
@Override
public JSONObject put(String name, double value) throws JSONException {
// TODO Auto-generated method stub
return put(name, value);
}
@Override
public JSONObject put(String name, int value) throws JSONException {
// TODO Auto-generated method stub
return put(name, value);
}
@Override
public JSONObject put(String name, long value) throws JSONException {
// TODO Auto-generated method stub
return put(name, value);
}
public JSONObject put(String key, Object value) throws JSONException {
if (key == null) {
throw new JSONException("Null key.");
}
if (value != null) {
testValidity(value);
mHashMap.put(key, value);
} else {
remove(key);
}
return this;
}
public Object remove(String key) {
return mHashMap.remove(key);
}
static void testValidity(Object o) throws JSONException {
if (o != null) {
if (o instanceof Double) {
if (((Double) o).isInfinite() || ((Double) o).isNaN()) {
throw new JSONException("JSON does not allow non-finite numbers.");
}
} else if (o instanceof Float) {
if (((Float) o).isInfinite() || ((Float) o).isNaN()) {
throw new JSONException("JSON does not allow non-finite numbers.");
}
}
}
}
public String toString() {
try {
Iterator<Object> keys = mHashMap.keySet().iterator();
StringBuffer sb = new StringBuffer("{");
while (keys.hasNext()) {
if (sb.length() > 1) {
sb.append(',');
}
Object o = keys.next();
sb.append(quote(o.toString()));
sb.append(':');
sb.append(valueToString(mHashMap.get(o)));
}
sb.append('}');
return sb.toString();
} catch (Exception e) {
return null;
}
}
static String valueToString(Object value) throws JSONException {
if (value == null || value.equals(null)) {
return "null";
}
if (value instanceof JSONStringer) {
Object o;
try {
o = ((JSONStringer) value).toString();
} catch (Exception e) {
throw new JSONException(e.getMessage());
}
if (o instanceof String) {
return (String) o;
}
throw new JSONException("Bad value from toJSONString: " + o);
}
if (value instanceof Number) {
return numberToString((Number) value);
}
if (value instanceof Boolean || value instanceof JSONObject || value instanceof JSONArray) {
return value.toString();
}
if (value instanceof Map) {
return new JSONObject((Map) value).toString();
}
if (value instanceof Collection) {
return new JSONArray((Collection) value).toString();
}
return quote(value.toString());
}
}