簡介
Comparable和 Comparator都是java.util包下的兩個接口,從字面上看這兩個接口都是用來做比較用的,但是jdk裡面不可能定義兩個功能相同的接口,是以他們肯定有不同的用處。
1、Comparable
1.1 說明
Comparable可以認為是一個内比較器,實作了Comparable接口的類有一個特點,就是這些 類是可以和自己比較的,至于具體和另一個實作了Comparable接口的類如何比較,則依賴compareTo方法的實作,compareTo方法也被稱為自然比較方法。如果開發者add進入一個Collection的對象想要Collections的sort方法幫你自動進行排序的話,那麼這個對象必須實作Comparable接口。compareTo方法的傳回值是int,有三種情況:
1、比較者大于被比較者(也就是compareTo方法裡面的對象),那麼傳回正整數
2、比較者等于被比較者,那麼傳回0
3、比較者小于被比較者,那麼傳回負整數
1.2 舉例
1.定義一個Girl.java類,實作Comparable接口,并且重寫compareTo方法:預設比較的是目前Girl類,通過age屬性進行比較。
public class Girl implements Comparable<Object> {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Girl(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Girl [name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Object o) {
Girl g = (Girl)o;
return this.age - g.getAge();
}
}
2.定義測試類Test.java,定義一個ArrayList儲存75個Girl,打亂順序後(因為List本身是有序的),檢視輸出結果。代碼如下:
public static void main(String[] args) {
List<Girl> list = new ArrayList<>(100);
Girl girl;
for (int i=0; i<75; i++) {
girl = new Girl("girl " + i, i);
list.add(girl);
}
Collections.shuffle(list);
list.stream().forEach(System.out::println);
}
輸出結果:
Girl [name=girl 9, age=9]
Girl [name=girl 60, age=60]
Girl [name=girl 26, age=26]
Girl [name=girl 55, age=55]
Girl [name=girl 12, age=12]
Girl [name=girl 31, age=31]
Girl [name=girl 49, age=49]
Girl [name=girl 6, age=6]
…
輸出是亂序的
3、還是2中的方法,隻不過添加一行代碼:使用Collections的sort(T t)方法排序。
public static void main(String[] args) {
List<Girl> list = new ArrayList<>(100);
Girl girl;
for (int i=0; i<75; i++) {
girl = new Girl("girl " + i, i);
list.add(girl);
}
Collections.shuffle(list);
Collections.sort(list);
list.stream().forEach(System.out::println);
}
輸出結果:
Girl [name=girl 0, age=0]
Girl [name=girl 1, age=1]
Girl [name=girl 2, age=2]
Girl [name=girl 3, age=3]
Girl [name=girl 4, age=4]
Girl [name=girl 5, age=5]
Girl [name=girl 6, age=6]
Girl [name=girl 7, age=7]
Girl [name=girl 8, age=8]
Girl [name=girl 9, age=9]
Girl [name=girl 10, age=10]
Girl [name=girl 11, age=11]
…
輸出是有序的,并且是按compareTo方法中定義的根據age的升序比較。
2、Comparator
2.1 說明
Comparator可以認為是是一個外比較器,個人認為有兩種情況可以使用實作Comparator接口的方式:
1、一個對象不支援自己和自己比較(沒有實作Comparable接口),但是又想對兩個對象進行比較。
2、一個對象實作了Comparable接口,但是開發者認為compareTo方法中的比較方式并不是自己想要的那種比較方式。
Comparator接口裡面有一個compare方法,方法有兩個參數T o1和T o2,是泛型的表示方式,分别表示待比較的兩個對象,方法傳回值和Comparable接口一樣是int,有三種情況:
1、o1大于o2,傳回正整數
2、o1等于o2,傳回0
3、o1小于o3,傳回負整數
2.2 舉例
1.定義一個Girl.java類如下:
public class Girl {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Girl(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Girl [name=" + name + ", age=" + age + "]";
}
}
2.定義GirlComparator.java類,實作Comparator接口,重寫compare()方法,和前面一樣根據age進行比較。
public class GirlComparator implements Comparator<Girl> {
@Override
public int compare(Girl g1, Girl g2) {
return g1.getAge() - g2.getAge();
}
}
2.定義測試類Test.java,定義一個TreeSet儲存75個Girl,檢視輸出結果。代碼如下:
public static void main(String[] args) {
Set<Girl> set = new TreeSet<>();
Girl girl;
for (int i = 0; i< 75; i++) {
girl = new Girl("girl "+i, i);
set.add(girl);
}
set.stream().forEach(System.out::println);
}
輸出結果:
Girl [name=girl 0, age=0]
Girl [name=girl 1, age=1]
Girl [name=girl 2, age=2]
Girl [name=girl 3, age=3]
Girl [name=girl 4, age=4]
Girl [name=girl 5, age=5]
Girl [name=girl 6, age=6]
Girl [name=girl 7, age=7]
Girl [name=girl 8, age=8]
Girl [name=girl 9, age=9]
Girl [name=girl 10, age=10]
Girl [name=girl 11, age=11]
Girl [name=girl 12, age=12]
…
輸出是有序的,并且是按compare方法中定義的根據age的升序比較。
3、總結
總結一下,這兩種比較器Comparable和Comparator,後者相比前者有如下優點:
- 個性化比較:如果實作類沒有實作Comparable接口,又想對兩個類進行比較(或者實作類實作了Comparable接口,但是對compareTo方法内的比較算法不滿意),那麼可以實作Comparator接口,自定義一個比較器,寫比較算法。
- 解耦:實作Comparable接口的方式比實作Comparator接口的耦合性要強一些,如果要修改比較算法,要修改Comparable接口的實作類,而實作Comparator的類是在外部進行比較的,不需要對實作類有任何修改。從這個角度說,其實有些不太好,尤其在我們将實作類的.class檔案打成一個.jar檔案提供給開發者使用的時候。