Comparable和Comparator的區別

(項目遇到的問題,須要比較一個類,我讓類實現了Comparable接口重寫了類的compareTo方法。Java沒有報錯,但應用的Sonar 靜態檢查掃描報了一個問題:重寫compareTo()原則上要重寫equals(),那不是還得重寫hashcode()??html

This class defines a compareTo(...) method but inherits its equals() method from java.lang.Object. Generally, the value of compareTo should return zero if and only if equals returns true. If this is violated, weird and unpredictable failures will occur in classes such as PriorityQueue. In Java 5 the PriorityQueue.remove method uses the compareTo method, while in Java 6 it uses the equals method.java

From the JavaDoc for the compareTo method in the Comparable interface:面試

It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y)). Generally speaking, any class that implements the Comparable interface and violates this condition should clearly indicate this fact. The recommended language is "Note: this class has a natural ordering that is inconsistent with equals."

後來改爲了使用Comparator。Collections.sort(List<T> list, Comparator<? super T>),這樣不用對類進行修改算法

編程

 

 

 

初次碰到這個問題是以前有一次電話面試,問了一個小時的問題,其中有一個問題就問到Comparable和Comparator的區別,當時沒答出 來。以後是公司入職時候作的一套Java編程題,裏面用JUnit跑用例的時候也用到了Comparator接口,再加上JDK的大量的類包括常見的 String、Byte、Char、Date等都實現了Comparable接口,所以要學習一下這兩個類的區別以及用法。dom

 

Comparablepost

Comparable能夠認爲是一個內比較器,實現了Comparable接口的類有一個特色,就是這些類是能夠和本身比較的,至於具體和另外一個實現了Comparable接口的類如何比較,則依賴compareTo方法的實現,compareTo方法也被稱爲天然比較方法若是開發者add進入一個Collection的對象想要Collections的sort方法幫你自動進行排序的話,那麼這個對象必須實現Comparable接口。compareTo方法的返回值是int,有三種狀況:學習

一、比較者大於被比較者(也就是compareTo方法裏面的對象),那麼返回正整數ui

二、比較者等於被比較者,那麼返回0this

三、比較者小於被比較者,那麼返回負整數

寫個很簡單的例子:

複製代碼
複製代碼
public class Domain implements Comparable<Domain>
{
    private String str;

    public Domain(String str)
    {
        this.str = str;
    }

    public int compareTo(Domain domain)
    {
        if (this.str.compareTo(domain.str) > 0)
            return 1;
        else if (this.str.compareTo(domain.str) == 0)
            return 0;
        else 
            return -1;
    }
    
    public String getStr()
    {
        return str;
    }
}
複製代碼
複製代碼
複製代碼
複製代碼
public static void main(String[] args)
    {
        Domain d1 = new Domain("c");
        Domain d2 = new Domain("c");
        Domain d3 = new Domain("b");
        Domain d4 = new Domain("d");
        System.out.println(d1.compareTo(d2));
        System.out.println(d1.compareTo(d3));
        System.out.println(d1.compareTo(d4));
    }
複製代碼
複製代碼

運行結果爲:

0
1
-1

注意一下,前面說實現Comparable接口的類是能夠支持和本身比較的,可是其實代碼裏面Comparable的泛型未必就必定要是Domain,將泛型指定爲String或者指定爲其餘任何任何類型均可以----只要開發者指定了具體的比較算法就行。

 

Comparator

Comparator能夠認爲是是一個外比較器,我的認爲有兩種狀況可使用實現Comparator接口的方式:

一、一個對象不支持本身和本身比較(沒有實現Comparable接口),可是又想對兩個對象進行比較

二、一個對象實現了Comparable接口,可是開發者認爲compareTo方法中的比較方式並非本身想要的那種比較方式

Comparator接口裏面有一個compare方法,方法有兩個參數T o1和T o2,是泛型的表示方式,分別表示待比較的兩個對象,方法返回值和Comparable接口同樣是int,有三種狀況:

一、o1大於o2,返回正整數

二、o1等於o2,返回0

三、o1小於o3,返回負整數

寫個很簡單的例子,上面代碼的Domain不變(假設這就是第2種場景,我對這個compareTo算法實現不滿意,要本身寫實現):

複製代碼
複製代碼
public class DomainComparator implements Comparator<Domain>
{
    public int compare(Domain domain1, Domain domain2)
    {
        if (domain1.getStr().compareTo(domain2.getStr()) > 0)
            return 1;
        else if (domain1.getStr().compareTo(domain2.getStr()) == 0)
            return 0;
        else 
            return -1;
    }
}
複製代碼
複製代碼
複製代碼
複製代碼
public static void main(String[] args)
{
    Domain d1 = new Domain("c");
    Domain d2 = new Domain("c");
    Domain d3 = new Domain("b");
    Domain d4 = new Domain("d");
    DomainComparator dc = new DomainComparator();
    System.out.println(dc.compare(d1, d2));
    System.out.println(dc.compare(d1, d3));
    System.out.println(dc.compare(d1, d4));
}
複製代碼
複製代碼

看一下運行結果:

0
1
-1

固然由於泛型指定死了,因此實現Comparator接口的實現類只能是兩個相同的對象(不能一個Domain、一個String)進行比較了,所以實現Comparator接口的實現類通常都會以"待比較的實體類+Comparator"來命名

 

總結

總結一下,兩種比較器Comparable和Comparator,後者相比前者有以下優勢:

一、若是實現類沒有實現Comparable接口,又想對兩個類進行比較(或者實現類實現了Comparable接口,可是對compareTo方法內的比較算法不滿意),那麼能夠實現Comparator接口,自定義一個比較器,寫比較算法

二、實現Comparable接口的方式比實現Comparator接口的耦合性 要強一些,若是要修改比較算法,要修改Comparable接口的實現類,而實現Comparator的類是在外部進行比較的,不須要對實現類有任何修 改。從這個角度說,其實有些不太好,尤爲在咱們將實現類的.class文件打成一個.jar文件提供給開發者使用的時候。實際上實現Comparator 接口的方式後面會寫到就是一種典型的策略模式

固然,這不是鼓勵用Comparator,意思是開發者仍是要在具體場景下選擇最合適的那種比較器而已。

 
 
 https://www.cnblogs.com/szlbm/p/5504634.html
相關文章
相關標籤/搜索