java 中Comparable與Comparator詳解與比較
java 中Comparable與Comparator詳解
今天查看TreeMap的源碼,發(fā)現(xiàn)其鍵必須是實現(xiàn)Comparable或者Comparator的接口時產(chǎn)生了一些興趣,比如在TreeMap中的put方法分別對Comparable和Comparator接口分別進(jìn)行處理。那么疑問就來了,Comparable和Comparator接口的區(qū)別是什么,Java中為什么會存在兩個類似的接口?
Comparable和Comparator接口都是用來比較大小的,首先來看一下Comparable的定義:
package java.lang;
import java.util.*;
public interface Comparable<T> {
public int compareTo(T o);
}
Comparator的定義如下:
package java.util;
public interface Comparator<T> {
int compare(T o1, T o2);
boolean equals(Object obj);
}
Comparable對實現(xiàn)它的每個類的對象進(jìn)行整體排序。這個接口需要類本身去實現(xiàn)(這句話沒看懂?沒關(guān)系,接下來看個例子就明白了)。若一個類實現(xiàn)了Comparable 接口,實現(xiàn) Comparable 接口的類的對象的 List 列表 ( 或數(shù)組)可以通過 Collections.sort(或 Arrays.sort)進(jìn)行排序。此外,實現(xiàn) Comparable 接口的類的對象 可以用作 “有序映射 ( 如 TreeMap)” 中的鍵或 “有序集合 (TreeSet)” 中的元素,而不需要指定比較器。
舉例(類Person1實現(xiàn)了Comparable接口)
package collections;
public class Person1 implements Comparable<Person1>
{
private int age;
private String name;
public Person1(String name, int age)
{
this.name = name;
this.age = age;
}
@Override
public int compareTo(Person1 o)
{
return this.age-o.age;
}
@Override
public String toString()
{
return name+":"+age;
}
}
可以看到Person1實現(xiàn)了Comparable接口中的compareTo方法。實現(xiàn)Comparable接口必須修改自身的類,即在自身類中實現(xiàn)接口中相應(yīng)的方法。
測試代碼:
Person1 person1 = new Person1("zzh",18);
Person1 person2 = new Person1("jj",17);
Person1 person3 = new Person1("qq",19);
List<Person1> list = new ArrayList<>();
list.add(person1);
list.add(person2);
list.add(person3);
System.out.println(list);
Collections.sort(list);
System.out.println(list);
輸出結(jié)果:
[zzh:18, jj:17, qq:19] [jj:17, zzh:18, qq:19]
如果我們的這個類無法修改,譬如String,我們又要對其進(jìn)行排序,當(dāng)然String中已經(jīng)實現(xiàn)了Comparable接口,如果單純的用String舉例就不太形象。對類自身無法修改這就用到了Comparator這個接口(策略模式)。
public final class Person2
{
private int age;
private String name;
public Person2(String name, int age)
{
this.name = name;
this.age = age;
}
@Override
public String toString()
{
return name+":"+age;
}
//getter and setter方法省略....
}
如類Person2,這個類已經(jīng)固定,無法進(jìn)行對其類自身的修改,也修飾詞final了,你也別想繼承再implements Comparable,那么此時怎么辦呢?在類的外部使用Comparator的接口。如下測試代碼:
Person2 p1 = new Person2("zzh",18);
Person2 p2 = new Person2("jj",17);
Person2 p3 = new Person2("qq",19);
List<Person2> list2 = new ArrayList<Person2>();
list2.add(p1);
list2.add(p2);
list2.add(p3);
System.out.println(list2);
Collections.sort(list2,new Comparator<Person2>(){
@Override
public int compare(Person2 o1, Person2 o2)
{
if(o1 == null || o2 == null)
return 0;
return o1.getAge()-o2.getAge();
}
});
System.out.println(list2);
輸出結(jié)果:
[zzh:18, jj:17, qq:19] [jj:17, zzh:18, qq:19]
這里(public static <T> void sort(List<T> list, Comparator<? super T> c) )采用了內(nèi)部類的實現(xiàn)方式,實現(xiàn)compare方法,對類Person2的list進(jìn)行排序。
再譬如博主遇到的真實案例中,需要對String進(jìn)行排序,且不區(qū)分大小寫,我們知道String中的排序是字典排序,譬如:A a D排序之后為A D a,這樣顯然不對,那么該怎么辦呢?同上(下面代碼中的list是一個String的List集合):
Collections.sort(list, new Comparator<String>()
{
@Override
public int compare(String o1, String o2)
{
if(o1 == null || o2 == null)
return 0;
return o1.toUpperCase().compareTo(o2.toUpperCase());
}
});
這樣就可以實現(xiàn)不區(qū)分大小進(jìn)行排序String的集合了,是不是很方便~
細(xì)心的同學(xué)可能會有疑問,明明在Comparator接口中定義了兩個方法,為什么繼承的時候只實現(xiàn)了一個方法,難道要顛覆我對Java接口常識的理解了???
實際上,我們知道當(dāng)一個類沒有顯式繼承父類的時候,會有一個默認(rèn)的父類,即java.lang.Object,在Object類中有一個方法即為equals方法,所以這里并不強制要求實現(xiàn)Comparator接口的類要實現(xiàn)equals方法,直接調(diào)用父類的即可,雖然你顯式的實現(xiàn)了equals()方法 will be a better choice~
在《Effective Java》一書中,作者Joshua Bloch推薦大家在編寫自定義類的時候盡可能的考慮實現(xiàn)一下Comparable接口,一旦實現(xiàn)了Comparable接口,它就可以跟許多泛型算法以及依賴于改接口的集合實現(xiàn)進(jìn)行協(xié)作。你付出很小的努力就可以獲得非常強大的功能。
事實上,Java平臺類庫中的所有值類都實現(xiàn)了Comparable接口。如果你正在編寫一個值類,它具有非常明顯的內(nèi)在排序關(guān)系,比如按字母順序、按數(shù)值順序或者按年代順序,那你就應(yīng)該堅決考慮實現(xiàn)這個接口。
compareTo方法不但允許進(jìn)行簡單的等同性進(jìn)行比較,而且語序執(zhí)行順序比較,除此之外,它與Object的equals方法具有相似的特征,它還是一個泛型。類實現(xiàn)了Comparable接口,就表明它的實例具有內(nèi)在的排序關(guān)系,為實現(xiàn)Comparable接口的對象數(shù)組進(jìn)行排序就這么簡單: Arrays.sort(a);
對存儲在集合中的Comparable對象進(jìn)行搜索、計算極限值以及自動維護(hù)也同樣簡單。列如,下面的程序依賴于String實現(xiàn)了Comparable接口,它去掉了命令行參數(shù)列表中的重復(fù)參數(shù),并按字母順序打印出來:
public class WordList{
public static void main(String args[]){
Set<String> s = new TreeSet<String>();
Collections.addAll(s,args);
System.out.println(s);
}
}
Comparable 是排序接口;若一個類實現(xiàn)了 Comparable 接口,就意味著 “該類支持排序”。而 Comparator 是比較器;我們?nèi)粜枰刂颇硞€類的次序,可以建立一個 “該類的比較器” 來進(jìn)行排序。
前者應(yīng)該比較固定,和一個具體類相綁定,而后者比較靈活,它可以被用于各個需要比較功能的類使用??梢哉f前者屬于 “靜態(tài)綁定”,而后者可以 “動態(tài)綁定”。
我們不難發(fā)現(xiàn):Comparable 相當(dāng)于 “內(nèi)部比較器”,而 Comparator 相當(dāng)于 “外部比較器”。
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
相關(guān)文章
Java項目Guava包?HashMultimap使用及注意事項
guava基本上可以說是java開發(fā)項目中,大概率會引入的包,今天介紹的主角是一個特殊的容器HashMultmap,可以簡單的將它的數(shù)據(jù)結(jié)構(gòu)理解為Map<K,?Set<V>>,今天主要介紹下基礎(chǔ)的知識點?HashMultmap級使用,感興趣的朋友一起看看吧2022-05-05
Java數(shù)組優(yōu)點和缺點_動力節(jié)點Java學(xué)院整理
本文給大家簡單介紹下java數(shù)組的優(yōu)點和缺點知識,需要的的朋友參考下吧2017-04-04
詳解SpringMVC使用MultipartFile實現(xiàn)文件的上傳
本篇文章主要介紹了SpringMVC使用MultipartFile實現(xiàn)文件的上傳,本地的文件上傳到資源服務(wù)器上,比較好的辦法就是通過ftp上傳。這里是結(jié)合SpringMVC+ftp的形式上傳的,有興趣的可以了解一下。2016-12-12
mall整合SpringSecurity及JWT認(rèn)證授權(quán)實戰(zhàn)下
這篇文章主要為大家介紹了mall整合SpringSecurity及JWT認(rèn)證授權(quán)實戰(zhàn)第二篇,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
SpringCloud OpenFeign自定義結(jié)果解碼器方式
這篇文章主要介紹了SpringCloud OpenFeign自定義結(jié)果解碼器方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09

