概要:
Comparable和Comparator都是用於比較數據的大小的,實現Comparable接口需要重寫compareTo方法,實現Comparator接口需要重寫compare方法,這兩個方法的返回值都是int,用int類型的值來確定比較結果,在Collections工具類中有一個排序方法sort,此方法可以之傳一個集合,另一個重載版本是傳入集合和比較器,前者默認使用的就是Comparable中的compareTo方法,後者使用的便是我們傳入的比較器Comparator,java的很多類已經實現了Comparable接口,比如說String,Integer等類,而我們其實也是基於這些實現了Comparator或者Comparab接口的原生類來比較我們自己的類,比如說自定義一個類User,屬性有name和age,倆個user之間的比較無非就是比較name和age的大小。
Comparable:
Comparable接口中只有一個方法:
public int compareTo(T o);
調用此方法的對象,也就是this和o進行比較,若返回值大於0則this大於o,返回值等於0則是this等於o,返回值小於0則是this<o,而這個Comparable是直接在我們的自定義類User上實現,因爲this是需要一個明確的比較對象的,也就是一般情況下我們會在定義User類的時候有排序的需求,就要實現此接口。
import java.util.ArrayList; import java.util.Collections; import java.util.List; public class UserComparable implements Comparable<UserComparable> { private String name; private int age; public UserComparable(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "UserComparable{" + "name='" + name + '\'' + ", age=" + age + '}'; } @Override public int compareTo(UserComparable o) { if (this.name.compareTo(o.name)==0){ if (this.age == o.age){ return 0; }else if (this.age >o.age){ return 1; }else { return -1; } }else if (this.name.compareTo(o.name)>0){ return 1; }else { return -1; } } public static void main(String[] args) { List<UserComparable> list = new ArrayList<UserComparable>(); list.add(new UserComparable("gol",21)); list.add(new UserComparable("gol",19)); list.add(new UserComparable("xiao",21)); list.add(new UserComparable("long",21)); System.out.println("排序前:"+list); //排序規則:先按name排序,若name相等則再比較age Collections.sort(list); System.out.println("排序後:"+list); } }
輸出結果爲:
排序前:[UserComparable{name='gol', age=21}, UserComparable{name='gol', age=19}, UserComparable{name='xiao', age=21}, UserComparable{name='long', age=21}]
排序後:[UserComparable{name='gol', age=19}, UserComparable{name='gol', age=21}, UserComparable{name='long', age=21}, UserComparable{name='xiao', age=21}]
Comparator:
Comparator接口中方法很多,但是我們只需要實現一個,也是最重要的一個compare,也許有的人會好奇爲什麼接口中的方法可以不用實現,因爲這是JDK8以後的新特性,在接口中用default修飾的方法可以有方法體,在實現接口的時候可以不用重寫,可以類比抽象類。
int compare(T o1, T o2);
compare比較的o1和o2,返回值大於0則o1大於o2,依次類推,對於compare;來說this是誰不重要,所比較的兩個對象都已經傳入到方法中,所有Comparator就是有個外部比較器,在我們設計User初時,並不需要它有比較功能,在後期擴展業務是,Comparator的存在可以使我們在不修改源代碼的情況下來完成需求,只需要新定義一個比較器來實現Comparator,重寫compare方法並將User對象傳進去。
import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; public class User { private String name; private int age; public User(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } public static void main(String[] args) { List<User> list = new ArrayList<User>(); list.add(new User("gol", 21)); list.add(new User("gol", 19)); list.add(new User("xiao", 21)); list.add(new User("long", 21)); System.out.println("排序前:" + list); //排序規則:先按name排序,若name相等則再比較age //創建比較器對象 Comparator comparator = new UserComparator(); Collections.sort(list,comparator); System.out.println("排序後:" + list); } static class UserComparator implements Comparator<User> { @Override public int compare(User o1, User o2) { if (o1.name.compareTo(o2.name) == 0) { if (o1.age == o2.age) { return 0; } else if (o1.age > o2.age) { return 1; } else { return -1; } } else if (o1.name.compareTo(o2.name) > 0) { return 1; } else { return -1; } } } }
輸出結果爲:
排序前:[User{name='gol', age=21}, User{name='gol', age=19}, User{name='xiao', age=21}, User{name='long', age=21}]
排序後:[User{name='gol', age=19}, User{name='gol', age=21}, User{name='long', age=21}, User{name='xiao', age=21}]
結論:
java中大部分我們常用的數據類型的類都實現了Comparable接口,而僅僅只有一個抽象類RuleBasedCollator實現了Comparator接口 ,還是我們不常用的類,這並不是要用Comparab而不要使用Comparator,在設計初時有需求就選擇Comparable,若後期需要擴展或增加排序需求是,再增加一個比較器Comparator,畢竟能寫Collections.sort(arg1),沒人樂意寫Collections.sort(arg1,arg2)。