有时候希望服务器跟客户端通信的JSONObjectt的键值对顺序是固定的。
例如:
客户端提交一个JSONObject格式的数据,里面有三个键值对,分别是"a":"a" "b":"b" "c":"c"
服务端原封不动返回给客户端,这个客户端希望接到的是这样的
{"a":"a","b":"b","c":"c"}
1. 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();
}
再看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
2.使用fastjson.jar中的com.alibaba.fastjson.annotation.JSONType,用@JSONType来标注实体类
import com.alibaba.fastjson.annotation.JSONType;
@JSONType(orders = { "type", "content", "locationUrl"})
public class MessageDto {
private Sting type;
private String content;
private String locationUrl;
public MessageDto() {
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getLocationUrl() {
return locationUrl;
}
public void setLocationUrl(String locationUrl) {
this.locationUrl = locationUrl;
}
}
使用如下:
MessageDto msg = new MessageDto();
msg.setContent("1");
msg.setLocationUrl("2");
msg.setType(3);
那么com.alibaba.fastjson.JSON.toJSONString(msg),得到的就是
{"type":"3","content":"1","locationUrl":"2"},
这跟标注的
(orders = { "type", "content", "locationUrl"})
一致。
以上仅从技术角度来讨论。可能有的人会说,肯定不会有这样的需求,但我确实遇到过这样的需求。多谢。