【Android 一般进阶】固定JSONObject.toString()键值对顺序

转载自:http://blog.csdn.net/ben0612/article/details/44591161

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

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

例如:

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

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

[html]  view plain  copy
  1. {"a":"a","b":"b","c":"c"}  

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

[html]  view plain  copy
  1. 1. <pre name="code" class="html">     JSONObject object=new JSONObject();  
  2.         try {  
  3.             object.putOpt("b", "b");  
  4.             object.putOpt("a", "a");  
  5.             object.putOpt("c", "c");  
  6.         } catch (JSONException e) {  
  7.             // TODO Auto-generated catch block  
  8.             e.printStackTrace();  
  9.         }  
 

object.toString(),得到的是

[html]  view plain  copy
  1. {"b":"b","c":"c","a":"a"}  
与put进去时候的顺序不一致。

2.

[html]  view plain  copy
  1. JSONObject object=new JSONObject();  
  2.     try {  
  3.         object.putOpt("1", "1");  
  4.         object.putOpt("2", "2");  
  5.         object.putOpt("3", "3");  
  6.     } catch (JSONException e) {  
  7.         // TODO Auto-generated catch block  
  8.         e.printStackTrace();  
  9.     }  
object.toString(),得到的是
[html]  view plain  copy
  1. {"3":"3","2":"2","1":"1"}  
与put进去时候的顺序不一致

3.
[html]  view plain  copy
  1. JSONObject object=new JSONObject();  
  2.     try {  
  3.         object.putOpt("我", "我");  
  4.         object.putOpt("你", "你");  
  5.         object.putOpt("他", "他");  
  6.     } catch (JSONException e) {  
  7.         // TODO Auto-generated catch block  
  8.         e.printStackTrace();  
  9.     }  
object.toString(),得到的是
[html]  view plain  copy
  1. {"你":"你","他":"他","我":"我"}  

与put进去时候的顺序不一致。

以上三个例子,无论键和值是数字、字母还是中文,JSONObject put进去的顺序喝toString得到的顺序,是不一致的。



如果还有疑问,我们看看JSONObject的源码吧。

先看构造方法:

[html]  view plain  copy
  1. public JSONObject() {  
  2.     nameValuePairs = new HashMap<String, Object>();  
  3. }  
再看putOpt 以及put方法:
[html]  view plain  copy
  1.     public JSONObject putOpt(String name, Object value) throws JSONException {  
  2.         if (name == null || value == null) {  
  3.             return this;  
  4.         }  
  5.         return put(name, value);  
  6.     }  
  7.   
  8.     public JSONObject put(String name, Object value) throws JSONException {  
  9.         if (value == null) {  
  10.             nameValuePairs.remove(name);  
  11.             return this;  
  12.         }  
  13.         if (value instanceof Number) {  
  14.             // deviate from the original by checking all Numbers, not just floats & doubles  
  15.             JSON.checkDouble(((Number) value).doubleValue());  
  16.         }  
  17.         nameValuePairs.put(checkName(name), value);  
  18.         return this;  
  19.     }  
这下可明白了吧,其实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的几个方法。

[html]  view plain  copy
  1. public class MyJSONObject extends JSONObject {  
  2.   
  3.     private LinkedHashMap<Object, Object> mHashMap;  
  4.   
  5.     public ChatMsgJSONObject() {  
  6.         mHashMap = new LinkedHashMap<Object, Object>();  
  7.     }  
  8.   
  9.     @Override  
  10.     public JSONObject put(String name, boolean value) throws JSONException {  
  11.         // TODO Auto-generated method stub  
  12.         return put(name, value);  
  13.     }  
  14.   
  15.     @Override  
  16.     public JSONObject put(String name, double value) throws JSONException {  
  17.         // TODO Auto-generated method stub  
  18.         return put(name, value);  
  19.     }  
  20.   
  21.     @Override  
  22.     public JSONObject put(String name, int value) throws JSONException {  
  23.         // TODO Auto-generated method stub  
  24.         return put(name, value);  
  25.     }  
  26.   
  27.     @Override  
  28.     public JSONObject put(String name, long value) throws JSONException {  
  29.         // TODO Auto-generated method stub  
  30.         return put(name, value);  
  31.     }  
  32.   
  33.     public JSONObject put(String key, Object value) throws JSONException {  
  34.         if (key == null) {  
  35.             throw new JSONException("Null key.");  
  36.         }  
  37.         if (value != null) {  
  38.             testValidity(value);  
  39.             mHashMap.put(key, value);  
  40.         } else {  
  41.             remove(key);  
  42.         }  
  43.         return this;  
  44.     }  
  45.   
  46.     public Object remove(String key) {  
  47.         return mHashMap.remove(key);  
  48.     }  
  49.   
  50.     static void testValidity(Object o) throws JSONException {  
  51.         if (o != null) {  
  52.             if (o instanceof Double) {  
  53.                 if (((Double) o).isInfinite() || ((Double) o).isNaN()) {  
  54.                     throw new JSONException("JSON does not allow non-finite numbers.");  
  55.                 }  
  56.             } else if (o instanceof Float) {  
  57.                 if (((Float) o).isInfinite() || ((Float) o).isNaN()) {  
  58.                     throw new JSONException("JSON does not allow non-finite numbers.");  
  59.                 }  
  60.             }  
  61.         }  
  62.     }  
  63.   
  64.     public String toString() {  
  65.         try {  
  66.             Iterator<Object> keys = mHashMap.keySet().iterator();  
  67.             StringBuffer sb = new StringBuffer("{");  
  68.   
  69.             while (keys.hasNext()) {  
  70.                 if (sb.length() > 1) {  
  71.                     sb.append(',');  
  72.                 }  
  73.                 Object o = keys.next();  
  74.                 sb.append(quote(o.toString()));  
  75.                 sb.append(':');  
  76.                 sb.append(valueToString(mHashMap.get(o)));  
  77.             }  
  78.             sb.append('}');  
  79.             return sb.toString();  
  80.         } catch (Exception e) {  
  81.             return null;  
  82.         }  
  83.     }  
  84.   
  85.     static String valueToString(Object value) throws JSONException {  
  86.         if (value == null || value.equals(null)) {  
  87.             return "null";  
  88.         }  
  89.         if (value instanceof JSONStringer) {  
  90.             Object o;  
  91.             try {  
  92.                 o = ((JSONStringer) value).toString();  
  93.             } catch (Exception e) {  
  94.                 throw new JSONException(e.getMessage());  
  95.             }  
  96.             if (o instanceof String) {  
  97.                 return (String) o;  
  98.             }  
  99.             throw new JSONException("Bad value from toJSONString: " + o);  
  100.         }  
  101.         if (value instanceof Number) {  
  102.             return numberToString((Number) value);  
  103.         }  
  104.         if (value instanceof Boolean || value instanceof JSONObject || value instanceof JSONArray) {  
  105.             return value.toString();  
  106.         }  
  107.         if (value instanceof Map) {  
  108.             return new JSONObject((Map) value).toString();  
  109.         }  
  110.         if (value instanceof Collection) {  
  111.             return new JSONArray((Collection) value).toString();  
  112.         }  
  113.         return quote(value.toString());  
  114.     }  
  115.   
  116. }  
2.使用fastjson.jar中的com.alibaba.fastjson.annotation.JSONType,用@JSONType来标注实体类
[html]  view plain  copy
  1. import com.alibaba.fastjson.annotation.JSONType;  
  2. @JSONType(orders = { "type", "content", "locationUrl"})  
  3. public class MessageDto {  
  4.   
  5.     private Sting type;  
  6.     private String content;  
  7.     private String locationUrl;  
  8.   
  9.     public MessageDto() {  
  10.     }  
  11.   
  12.     public String getType() {  
  13.         return type;  
  14.     }  
  15.   
  16.     public void setType(String type) {  
  17.         this.type = type;  
  18.     }  
  19.   
  20.     public String getContent() {  
  21.         return content;  
  22.     }  
  23.   
  24.     public void setContent(String content) {  
  25.         this.content = content;  
  26.     }  
  27.   
  28.     public String getLocationUrl() {  
  29.         return locationUrl;  
  30.     }  
  31.         public void setLocationUrl(String locationUrl) {  
  32.                 this.locationUrl = locationUrl;  
  33.         }  
  34.  }  
使用如下:

[html]  view plain  copy
  1. MessageDto msg = new MessageDto();  
  2. msg.setContent("1");  
  3. msg.setLocationUrl("2");  
  4. msg.setType(3);  
那么com.alibaba.fastjson.JSON.toJSONString(msg),得到的就是
[html]  view plain  copy
  1. {"type":"3","content":"1","locationUrl":"2"},  
这跟标注的
[html]  view plain  copy
  1. (orders = { "type", "content", "locationUrl"})  
一致。


以上仅从技术角度来讨论。可能有的人会说,肯定不会有这样的需求,但我确实遇到过这样的需求。多谢。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值