似懂非懂的Comparable與Comparator

jdk1.8.0_144html

只知其一;不知其二寫代碼, 集合排序用個啥。 抄起鍵盤胡亂打, 似懂非懂最可怕。程序員

  Comparable與Comparator都是用於集合的排序,對於大多數人來講Comparator可能略微比Comparable要熟悉一點,相似下面這幾句代碼的使用頻率應該是最高的。設計模式

Collections.sort(list, new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        return o1.compareTo(o2);
    }
});

  這是一段對集合排序的代碼。數組

  對於集合排序時比較器的使用每每止步於此,以致於更爲深層次的使用似懂非懂,更爲複雜的排序不知所措。ide

  Comparable用於集合內部定義的方法實現的排序,Comparator用於集合外部實現的排序。函數

  咱們從Collections.sort的兩個重載方法開始學習

public static <T extends Comparable<? super T>> void sort(List<T> list) spa

public static <T> void sort(List<T> list, Comparator<? super T> c) 設計

  這兩個方法都是泛型方法,第一個方法只傳遞一個List參數進行排序,第二個方法傳遞一個List參數加上一個Comparator比較器。code

 

public static <T extends Comparable<? super T>> void sort(List<T> list)

  Collections.sort方法用於對List集合進行排序,思考一個問題,這個只有一個參數的List如何進行排序呢?它是按照怎樣的規則進行排序呢?答案就在這個泛型方法的泛型類型之中「<T extends Comparable<? super T>>」,List集合中的元素須要實現Comparable接口,Comparable接口也是一個泛型,並要求它的泛型類型須要是集合中的元素的超類(或自身)。重點在於——集合中的元素須要是實現Comparable接口。也就是說在使用Collections.sort(List)這個方法對集合中的元素進行排序時,須要集合中的元素實現了Comparable接口,這才能進行排序。

 

public static <T> void sort(List<T> list, Comparator<? super T> c)

  這個方法一樣是一個泛型方法,與上面的方法不一樣的是對集合中的元素類型並無作限制,要對這個集合進行排序須要指定一個Comparator比較器,這個比較器的泛型類型須要是集合元素的超類(或自身)。

  經過上面這兩個方法比較容易的能得出一個淺顯的結論,Comparable和Comparator都是用於比較、排序,若是元素自身已經實現了Comparable接口,則能夠利用它自身進行比較排序,若是元素自身沒有實現Comparable接口,則能夠利用外部實現Comparator比較器對元素進行比較排序。這也就是前面提到的Comparable用於集合內部定義的方法實現的排序,Comparator用於集合外部實現的排序。 接着來看Comparable接口和Comparator接口。

 

  接着來看Comparable接口和Comparator接口。

Comparable

public int compareTo(T o)

  這個接口只定義了一個compareTo方法,在不少「值類型」的數據類型,例如String、Integer、Long等已經實現了這個接口。

  對於這個方法和equals方法有相似的地方,equals強調的更可能是相等於否,而compareTo強調更多的比較,若是x < y,則返回-1;x = y,則返回0;x > y,則返回1。實現這個方法時一樣須要遵循幾個規則:

  1. 自反性,若是x <y ,那麼x.compareTo(y)返回-1,同理y.compareTo則返回1;
  2. 傳遞性,若是x.compareTo(y)返回-1,y.compareTo(z)返回-1,則x.compareTo(z)也應該返回-1;
  3. 同一性,若是x.compareTo(y)返回0(x = y),那麼若x.compareTo(z)返回-1時,y.compareTo(z)也應該返回-1。

  有興趣的能夠查看String類中對於compareTo方法的實現,它的排序規則是將字符串轉換爲字符數組逐個按照字典序排序。

 

Comparator

int compare(T o1, T o2)

boolean equals(Object obj)

  這個接口在JDK8中對它進行了較大的改進,在JDK8以前只包含上面兩個方法,而JDK8則達到了18個方法,其中都是接口的default方法,和static靜態方法,因此並不須要在實現時額外實現。

  在JDK8中該類添加了@FunctionalInterface函數式接口的註解,函數式接口代表在接口中只含有一個方法做爲Lambda表達式的數據類型,在《JDK8的新特性——Lambda表達式》中有提到,Java中定義若是覆蓋了Object中的方法則不算,因此在Comparator接口中只有一個compare方法。對於@FunctionalInteface註解可加不可加,加上只是爲了讓編譯器作更好的檢查,要求只能定義一個方法,不加編譯器便不對此進行檢查。

  compare方法和compareTo方法相似,它一樣須要知足上面提到的:自反性、傳遞性、同一性。而且它強調,沒必要嚴格知足「(compare(x, y)==0) == (x.equals(y))」,固然最好說明白。

  對於這個類,更多的是須要理解學習它所運用的設計模式——策略模式。策略模式,不改變對象自身,而是用另外一個對象來改變它的行爲。例如,超市減價操做,有10件商品須要統一降價1半進行處理,咱們能夠在這10件商品的價格上所有作修改減小至它的一半,10件好處理,若是N件呢,甚至咱們還須要對其進行降價呢?此時咱們則可使用一種「策略」——商品所有打5折。這就是利用另一個對象來改變一個對象的行爲,而不是簡單粗暴地修改原有對象。說回此處,若是List中的元素自己沒有實現Comparable接口,但咱們須要對它進行排序,咱們能夠對原有對象進行修改讓它實現Comparable接口,但凡涉及修改代碼都不優美,此時咱們則能夠利用策略模式,也就是實現一個Comparator接口對集合中的元素進行排序。

 

 

這是一個能給程序員加buff的公衆號 

相關文章
相關標籤/搜索