固定JSONObject.toString()键值对顺序

org.json.JSONObject相信很多人都用过,例如:服务端返回给客户端的数据格式是JSONObject的,那我们通过对它进行解析,把它显示在界面上。

有时候希望服务器跟客户端通信的JSONObjectt的键值对顺序是固定的。

例如:

客户端提交一个JSONObject格式的数据,里面有三个键值对,分别是"a":"a" "b":"b" "c":"c"

服务端原封不动返回给客户端,这个客户端希望接到的是这样的

{"a":"a","b":"b","c":"c"}


但JSONObject的键值对顺序几乎不能确定的,无规律可循,验证如下:

1. <pre name="code" class="html">

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

object.toString(),得到的是

{"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,int value) throws JSONException {
// Todo Auto-generated method stub
return put(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());
}

}

相关文章

AJAX是一种基于JavaScript和XML的技术,能够使网页实现异步交...
在网页开发中,我们常常需要通过Ajax从后端获取数据并在页面...
在前端开发中,经常需要循环JSON对象数组进行数据操作。使用...
AJAX(Asynchronous JavaScript and XML)是一种用于创建 We...
AJAX技术被广泛应用于现代Web开发,它可以在无需重新加载页面...
Ajax是一种通过JavaScript和HTTP请求交互的技术,可以实现无...