java學習-排序及加密簽名時數據排序方式

排序有兩種html

1. 類實現comparable接口調用List.sort(null)或Collections.sort(List<T>)方法進行排序前端

jdk內置的基本類型包裝類等都實現了Comparablel接口,默認是使用天然排序,即升序排序java

自定義類實現Comparable接口必需要實現compareTo()方法,本身定義排序方式算法

2.另外一種是List<T>中T類沒有實現comparable接口,又想將對象列表進行排序時,相似於Collections.sort or Arrays.sort排序時候使用Comparator接口做爲參數進行集合的排序sql

 

上面的兩種排序方式底層都是採用歸併排序算法,是穩定的排序算法。時間複雜度(nlog2n),空間複雜度(n) 十大經典排序算法(動圖演示)api

 

使用場景:數組

1.調用別人接口獲取數據時候,須要將參數按照字典排序排序對數據進行簽名,與返回的簽名數據進行對比,驗證數據的完整性。微信

2.對獲取的數據進行排序後返回給前端,除了使用sql的order asc命令外,也可使用list.sort方法進行排序後返回給前端(有點傻^^)。app

3. 用於複雜的排序場景,好比文件名的排序,廣東-廣州-期末測試1,廣西-桂林-期末測試2,須要咱們本身控制排序方法,這時候就須要用到上面兩個排序。eclipse

 

實現Comparable接口的排序

consumInfo.java類

實現comparable接口,使用升序排序

降序就是取反

if (this.price > o.price) {
            return -1; } if (this.price == o.price) { return 0; } return 1;
public class ConsumInfo implements Comparable<ConsumInfo> {
    public double price;
    public String name;

    public ConsumInfo(double price, String name) {
        super();
        this.price = price;
        this.name = name;
    }

    @Override
    public int compareTo(ConsumInfo o) {
        // 首先比較price,若是price相同

        if (this.price > o.price) {
            return 1;
        }

        if (this.price == o.price) {
            return 0;
        }

        return -1;
    }
}

 

來個簡單的測試

        ConsumInfo []cc=new ConsumInfo[4];
        cc[0] = new ConsumInfo(1.1, "zwh");
        cc[1] = new ConsumInfo(2.5, "abc");
        cc[2] = new ConsumInfo(0.1, "zwh");
        cc[3] = new ConsumInfo(0.1, "cdf");
        Arrays.sort(cc);
        for(ConsumInfo consumInfo:cc) {
            System.out.println("name:"+consumInfo.name+"  price:"+consumInfo.price);
        }
結果

name:zwh price:0.1
name:cdf price:0.1
name:zwh price:1.1
name:abc price:2.5

 

若是要先按照price排序,若是price相等,再按name進行升序排序呢

只須要修改conpareTo()方法,在price相等時,在比較name的值

    @Override
    public int compareTo(ConsumInfo o) {
        // 首先比較price,若是price相同

        if (this.price > o.price) {
            return 1;
        }
        
        if(this.price==o.price) {
            return this.name.compareTo(o.name);
        }

        return -1;
    }

修改後的輸出結果,

這裏name是String類型,默認是按照字典順序排序,也就是升序排序。

cdf和zwh,,c比z小,因此調換了位置

name:cdf  price:0.1
name:zwh  price:0.1
name:zwh  price:1.1
name:abc  price:2.5

使用Comparator接口實現排序 

仍是使用上面的ConsumInfo.java類

        ConsumInfo []cc=new ConsumInfo[4];
        cc[0] = new ConsumInfo(1.1, "zwh");
        cc[1] = new ConsumInfo(2.5, "abc");
        cc[2] = new ConsumInfo(0.1, "zwh");
        cc[3] = new ConsumInfo(0.1, "cdf");
        Arrays.sort(cc,new Comparator<ConsumInfo>() {

            @Override
            public int compare(ConsumInfo o1, ConsumInfo o2) {
                if(o1.price<o2.price) {
                    return -1;
                }
                if(o1.price==o2.price) {
                    return o1.name.compareTo(o2.name);
                }
                return 1;
            }
        });
        for(ConsumInfo consumInfo:cc) {
            System.out.println("name:"+consumInfo.name+"  price:"+consumInfo.price);
        }

使用了Arrays.sort(T[] a, Comparator<? super T> c)排序方法,會把ConsumInfo所實現的Comparable接口的排序方法替換掉

也就是說只會使用Comparator接口進行排序。

上面的排序是用於List或者數組或集合的排序,

對於Map,須要對map的key值進行升序排序

使用TreeMap類進行自動排序,默認升序排序。

        Map<String, String> para = new TreeMap<String, String>();
        para.put("zwh", "123456");
        para.put("abc", "123456");
        para.put("wuv", "123456");
        para.put("cdg", "123456");

        for (Map.Entry<String, String> entry : para.entrySet()) {
            System.out.println("key:" + entry.getKey() + " value:" + entry.getValue());
        }
結果

key:abc value:123456
key:cdg value:123456
key:wuv value:123456
key:zwh value:123456

 

 

或者咱們本身手動對map的key值進行排序 參考:【支付寶,微信支付必備】Java實現url參數按照參數名Unicode碼從小到大排序(字典序)

/** 
    *  
    * 方法用途: 對全部傳入參數按照字段名的Unicode碼從小到大排序(字典序),而且生成url參數串<br> 
    * 實現步驟: <br> 
    *  
    * @param paraMap   要排序的Map對象 
    * @param urlEncode   是否須要對value的值進行編碼
    * @param keyToLower    是否須要將Key轉換爲全小寫 
    *            true:key轉化成小寫,false:不轉化 
    * @return 
    */
    public static String formatUrlMap(Map<String, String> paraMap, boolean urlEncode, boolean keyToLower) {
        String buff = "";
        Map<String, String> tmpMap = paraMap;
        try {
            List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(tmpMap.entrySet());
            // 對全部傳入參數按照字段名的 ASCII 碼從小到大排序(字典序)
            Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>() {

                @Override
                public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
                    return (o1.getKey()).toString().compareTo(o2.getKey());
                }
            });
            // 構造URL 鍵值對的格式
            StringBuilder buf = new StringBuilder();
            for (Map.Entry<String, String> item : infoIds) {
                if (item.getKey() != null) {
                    String key = item.getKey();
                    String val = item.getValue();
                    if (urlEncode) {
                        val = URLEncoder.encode(val, "utf-8");
                    }
                    if (keyToLower) {
                        buf.append(key.toLowerCase() + "=" + val);
                    } else {
                        buf.append(key + "=" + val);
                    }

                    buf.append("&");
                }

            }
            buff = buf.toString();
            if (buff.isEmpty() == false) {
                buff = buff.substring(0, buff.length() - 1);
            }
        } catch (Exception e) {
            return null;
        }
        return buff;
    }

 

參考支付寶的參數排序方法

剔除sign字段(這個根本不須要剔除,參數中是沒有的),

剔除參數值爲空的字段,這裏作了個簡單的判斷,

對key進行排序,而後用&符號對key=value進行拼接。

        Map<String, String> para = new TreeMap<String, String>();
        para.put("app_id", "2014072300007148");
        para.put("method", "alipay.mobile.public.menu.add");
        para.put("charset", "");
        para.put("sign_type", "");
        para.put("timestamp", "2014-07-24 03:07:50");
        para.put("biz_content", "");
        para.put("sign_type", "123456");
        para.put("version", "1.0");

        List<String> keys= new ArrayList<>(para.keySet());
        Collections.sort(keys);
        StringBuffer content=new StringBuffer();
        for (int i=0; i<keys.size();i++) {
            String key = keys.get(i);
            String value = para.get(key);
            if(value!=null&&value.length()!=0) {
                content.append((i==0?"":"&")+key+"="+value);
            }
        }
        System.out.println(content.toString());

結果

app_id=2014072300007148&method=alipay.mobile.public.menu.add&sign_type=123456&timestamp=2014-07-24 03:07:50&version=1.0

 

注意,上面字符串的空判斷還少作了一個空白字符的判斷,建議使用下面的值的非空判斷代替

if(value!=null&&value.length()!=0)
public static boolean isBlank(String str) {
        int strLen;
        if (str == null || (strLen = str.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if ((Character.isWhitespace(str.charAt(i)) == false)) {
                return false;
            }
        }
        return true;
    }

 待看:http://www.cnblogs.com/interdrp/p/8970593.html Java Comparator字符排序(數字、字母、中文混合排序)

編寫高質量代碼:改善Java程序的151個建議(第5章:數組和集合___建議70~74)

相關文章
相關標籤/搜索