面試官:?jiǎn)栂禄A(chǔ),你能說(shuō)說(shuō)Java中Comparable和Comparator的區(qū)別嗎
之前面試中被問(wèn)到這個(gè)問(wèn)題,當(dāng)時(shí)不屑(會(huì))回答,下來(lái)特意查了查,整理如下。
Java 中為我們提供了兩種比較機(jī)制:Comparable 和 Comparator,二者都是用來(lái)實(shí)現(xiàn)對(duì)象的比較、排序。
下面分別對(duì)Comparable 和 Comparator做具體介紹并總結(jié)。
Comparable
Comparable可以認(rèn)為是一個(gè)內(nèi)比較器,實(shí)現(xiàn)了Comparable接口的類(lèi)有一個(gè)特點(diǎn),就是這些類(lèi)是可以和自己比較的,至于具體和另一個(gè)實(shí)現(xiàn)了Comparable接口的類(lèi)如何比較,則依賴(lài)compareTo方法的實(shí)現(xiàn)。
如果add進(jìn)入一個(gè)Collection的對(duì)象想要Collections的sort方法幫你自動(dòng)進(jìn)行排序的話(huà),那么這個(gè)對(duì)象必須實(shí)現(xiàn)Comparable接口。compareTo方法的返回值是int,有三種情況:
比較者大于被比較者,返回正整數(shù)
比較者等于被比較者,返回0
比較者小于被比較者,返回負(fù)整數(shù)
寫(xiě)個(gè)很簡(jiǎn)單的例子:
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));
}
運(yùn)行結(jié)果為:
0
1
-1
注意一下,前面說(shuō)實(shí)現(xiàn)Comparable接口的類(lèi)是可以支持和自己比較的,但是其實(shí)代碼里面Comparable的泛型未必就一定要是Domain,將泛型指定為String或者指定為其他任何任何類(lèi)型都可以,只要開(kāi)發(fā)者指定了具體的比較算法就行。
Comparator
Comparator接口里面有一個(gè)compare方法,方法有兩個(gè)參數(shù)T o1和T o2,是泛型的表示方式,分別表示待比較的兩個(gè)對(duì)象,方法返回值和Comparable接口一樣是int,有三種情況:
o1大于o2,返回正整數(shù)
o1等于o2,返回0
o1小于o3,返回負(fù)整數(shù)
寫(xiě)個(gè)很簡(jiǎn)單的例子:
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));
}
看一下運(yùn)行結(jié)果:
0
1
-1
因?yàn)榉盒椭付ㄋ懒?,所以?shí)現(xiàn)Comparator接口的實(shí)現(xiàn)類(lèi)只能是兩個(gè)相同的對(duì)象(不能一個(gè)Domain、一個(gè)String)進(jìn)行比較了,實(shí)現(xiàn)Comparator接口的實(shí)現(xiàn)類(lèi)一般都會(huì)以"待比較的實(shí)體類(lèi)+Comparator"來(lái)命名
總結(jié)
如果實(shí)現(xiàn)類(lèi)沒(méi)有實(shí)現(xiàn)Comparable接口,又想對(duì)兩個(gè)類(lèi)進(jìn)行比較(或者實(shí)現(xiàn)類(lèi)實(shí)現(xiàn)了Comparable接口,但是對(duì)compareTo方法內(nèi)的比較算法不滿(mǎn)意),那么可以實(shí)現(xiàn)Comparator接口,自定義一個(gè)比較器,寫(xiě)比較算法。
實(shí)現(xiàn)Comparable接口的方式比實(shí)現(xiàn)Comparator接口的耦合性要強(qiáng)一些,如果要修改比較算法,要修改Comparable接口的實(shí)現(xiàn)類(lèi),而實(shí)現(xiàn)Comparator的類(lèi)是在外部進(jìn)行比較的,不需要對(duì)實(shí)現(xiàn)類(lèi)有任何修改。因此:
對(duì)于一些普通的數(shù)據(jù)類(lèi)型(比如 String, Integer, Double…),它們默認(rèn)實(shí)現(xiàn)了Comparable 接口,實(shí)現(xiàn)了 compareTo 方法,我們可以直接使用。
而對(duì)于一些自定義類(lèi),它們可能在不同情況下需要實(shí)現(xiàn)不同的比較策略,我們可以新創(chuàng)建 Comparator 接口,然后使用特定的 Comparator 實(shí)現(xiàn)進(jìn)行比較。
不同之處:
個(gè)人感覺(jué)說(shuō)出上文觀(guān)點(diǎn),這個(gè)提問(wèn)就算回答完了,如果非要說(shuō)不同之處,那就是:
Comparator位于java.util包下,而Comparable位于java.lang包下
實(shí)現(xiàn)Comparable接口的方式比實(shí)現(xiàn)Comparator接口的耦合性要強(qiáng)
等等………..
往期資源 需要請(qǐng)自取
往期資源 需要請(qǐng)自取
喜歡就"在看"唄^_^
