[英]When to use Comparable and Comparator
我有一個需要在字段上排序的對象列表,比如 Score。 我沒有多想就寫了一個實現 Comparator 的新類,它可以完成任務並且可以工作。
現在回想起來,我想知道我是否應該讓我的類實現 Comparable,而不是創建一個實現 Comparator 的新類。 分數是唯一可以對對象進行排序的字段。
我做了什么可以接受的做法?
正確的方法是“首先讓類實現 Comparable(用於自然排序),如果需要替代字段比較,然后創建一個實現 Comparator 的新類”?
如果上面的(2)是正確的,那么是否意味着只有在類實現了 Comparable 之后才應該實現 Comparator ? (假設我擁有原始類)。
如果要定義所討論對象的默認(自然)排序行為,請使用Comparable
,通常的做法是為此使用對象的技術或自然(數據庫?)標識符。
如果要定義外部可控排序行為,請使用Comparator
,這可以覆蓋默認排序行為。
我會說一個對象應該實現 Comparable 如果這是對類進行排序的清晰自然的方式,並且任何需要對類進行排序的人通常都希望這樣做。
但是,如果排序是類的不尋常使用,或者排序僅對特定用例有意義,那么 Comparator 是更好的選擇。
換句話說,給定類名,是否清楚可比較的排序方式,還是必須求助於閱讀 javadoc? 如果是后者,很可能每個未來的排序用例都需要比較器,此時可比較的實現可能會減慢該類的用戶的速度,而不是加快他們的速度。
使用Comparable
:
使用Comparator
:
Comparable
。Comparable
指定)不同的行為時。 Comparable - java.lang.Comparable: int compareTo(Object o1)
可比較對象能夠將自身與另一個對象進行比較。 類本身必須實現 java.lang.Comparable 接口才能比較其實例。
only one sort sequence
實現only one sort sequence
基於實例屬性的only one sort sequence
。 例如: Person.id
比較器- java.util.Comparator: int compare(Object o1, Object o2)
比較器對象能夠比較兩個不同的對象。 該類不是比較它的實例,而是比較其他一些類的實例。 這個比較器類必須實現 java.util.Comparator 接口。
many sort sequence
並命名每個。 例如: Person.id, Person.name, Person.age
例子:
public class Employee implements Comparable<Employee> {
private int id;
private String name;
private int age;
private long salary;
// Many sort sequences can be created with different names.
public static Comparator<Employee> NameComparator = new Comparator<Employee>() {
@Override
public int compare(Employee e1, Employee e2) {
return e1.getName().compareTo(e2.getName());
}
};
public static Comparator<Employee> idComparator = new Comparator<Employee>() {
@Override
public int compare(Employee e1, Employee e2) {
return Integer.valueOf(e1.getId()).compareTo(Integer.valueOf(e2.getId()));
}
};
public Employee() { }
public Employee(int id, String name, int age, long salary){
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
// setters and getters.
// Only one sort sequence can be created with in the class.
@Override
public int compareTo(Employee e) {
//return Integer.valueOf(this.id).compareTo(Integer.valueOf(e.id));
//return Character.toString(this.name.charAt(0)).compareToIgnoreCase(Character.toString(e.name.charAt(0)));
if (this.id > e.id) {
return 1;
}else if(this.id < e.id){
return -1;
}else {
return Character.toString(this.name.charAt(0)).compareToIgnoreCase(Character.toString(e.name.charAt(0)));
}
}
public static void main(String[] args) {
Employee e1 = new Employee(5, "Yash", 22, 1000);
Employee e2 = new Employee(8, "Tharun", 24, 25000);
List<Employee> list = new ArrayList<Employee>();
list.add(e1);
list.add(e2);
Collections.sort(list); // call @compareTo(o1)
Collections.sort(list, Employee.nameComparator); // call @compare (o1,o2)
Collections.sort(list, Employee.idComparator); // call @compare (o1,o2)
}
}
對於Java 8 Lambda:比較器,請參閱我的帖子。
當您比較同一類的實例時,應使用 Comparable。
比較器可用於比較不同類的實例。
Comparable 由需要為其對象定義自然順序的類實現。 例如,String 實現了 Comparable。
如果需要不同的排序順序,則實現比較器並定義自己的比較兩個實例的方式。
如果對象的排序需要基於自然順序,則使用 Comparable,而如果需要對不同對象的屬性進行排序,則使用 Java 中的 Comparator。
Comparable 和 Comparator 的主要區別:
+------------------------------------------------------------------------------------+
¦ Comparable ¦ Comparator ¦
¦-----------------------------------------+------------------------------------------¦
¦ java.lang.Comparable ¦ java.util.Comparator ¦
¦-----------------------------------------+------------------------------------------¦
¦ int objOne.compareTo(objTwo) ¦ int compare(objOne, objTwo) ¦
¦-----------------------------------------+------------------------------------------¦
¦ Negative, if objOne < objTwo ¦ Same as Comparable ¦
¦ Zero, if objOne == objTwo ¦ ¦
¦ Positive, if objOne > objTwo ¦ ¦
¦-----------------------------------------+------------------------------------------¦
¦ You must modify the class whose ¦ You build a class separate from to sort. ¦
¦ instances you want to sort. ¦ the class whose instances you want ¦
¦-----------------------------------------+------------------------------------------¦
¦ Only one sort sequence can be created ¦ Many sort sequences can be created ¦
¦-----------------------------------------+------------------------------------------¦
¦ Implemented frequently in the API by: ¦ Meant to be implemented to sort ¦
¦ String, Wrapper classes, Date, Calendar ¦ instances of third-party classes. ¦
+------------------------------------------------------------------------------------+
Comparator 可以完成可比較所做的一切,而且還有更多。
| | Comparable | Comparator ._______________________________________________________________________________ Is used to allow Collections.sort to work | yes | yes Can compare multiple fields | yes | yes Lives inside the class you're comparing and serves | | as a “default” way to compare | yes | yes Can live outside the class you're comparing | no | yes Can have multiple instances with different method names | no | yes Input arguments can be a list of | just Object| Any type Can use enums | no | yes
我發現使用比較器作為匿名類的最佳方法如下:
private static void sortAccountsByPriority(List<AccountRecord> accounts) {
Collections.sort(accounts, new Comparator<AccountRecord>() {
@Override
public int compare(AccountRecord a1, AccountRecord a2) {
return a1.getRank().compareTo(a2.getRank());
}
});
}
您可以在您計划排序的類中創建此類方法的多個版本。 所以你可以有:
sortAccountsByPriorityAndType
等等...
現在,您可以在任何地方使用這些排序方法並獲得代碼重用。 這給了我可比的一切,再加上更多......所以我根本看不到任何使用可比性的理由。
我會說:
以下幾點可以幫助您決定在哪些情況下應該使用 Comparable 以及在哪種 Comparator 中使用:
1) 代碼可用性
2) 單與多排序標准
3) Arays.sort() 和 Collection.sort()
4) 作為 SortedMap 和 SortedSet 中的鍵
5)更多的類與靈活性
6) 類間比較
7) 自然秩序
有關更詳細的文章,您可以參考何時使用可比較以及何時使用比較器
如果您需要自然順序排序 - User Comparable 如果您需要自定義順序排序 - 使用比較器
例子:
Class Employee{
private int id;
private String name;
private String department;
}
自然順序排序將基於 id,因為它是唯一的,而自定義順序排序將是姓名和部門。
參考資料:
什么時候類應該是 Comparable 和/或 Comparator? http://javarevisited.blogspot.com/2011/06/comparator-and-comparable-in-java.html
這里曾經有一個類似的問題: 一個類什么時候應該是 Comparable 和/或 Comparator?
我會說以下內容:為諸如自然排序之類的東西實現 Comparable,例如基於內部 ID
如果您有更復雜的比較算法,例如多個字段等,請實現 Comparator。
可比:
每當我們只想存儲同類元素和所需的默認自然排序順序時,我們可以使用實現comparable
接口的類。
比較器:
每當我們想要存儲同質和異質元素並且我們想要按照默認的自定義排序順序進行排序時,我們可以使用comparator
接口。
我的需求是根據日期排序的。
所以,我使用了 Comparable,它對我來說很容易。
public int compareTo(GoogleCalendarBean o) {
// TODO Auto-generated method stub
return eventdate.compareTo(o.getEventdate());
}
Comparable 的一個限制是它們不能用於列表以外的集合。
如果您擁有該課程,則最好使用Comparable 。 一般比較使用,如果你不擁有一流的,但你必須使用一個TreeSet或TreeMap的,因為比較可以在TreeSet中或樹形圖conctructor參數傳遞。 您可以在http://preciselyconcise.com/java/collections/g_comparator.php 中看到如何使用 Comparator 和 Comparable
在一次面試中,我被要求在比 nlogn 更好的時間內對一定范圍的數字進行排序。 (不使用計數排序)
在對象上實現 Comparable 接口允許隱式排序算法使用重寫的 compareTo 方法對元素排序,這將是線性時間。
Comparable 是為數值提供的默認自然排序順序是升序,字符串是按字母順序。 例如:
Treeset t=new Treeset();
t.add(2);
t.add(1);
System.out.println(t);//[1,2]
Comparator 是在自定義 myComparator 類中通過覆蓋比較方法實現的自定義排序順序,例如:
Treeset t=new Treeset(new myComparator());
t.add(55);
t.add(56);
class myComparator implements Comparator{
public int compare(Object o1,Object o2){
//Descending Logic
}
}
System.out.println(t);//[56,55]
非常簡單的方法是假設有問題的實體類在數據庫中表示,然后在數據庫表中您是否需要由實體類的字段組成的索引? 如果答案是肯定的,則實現可比較並使用索引字段進行自然排序。 在所有其他情況下使用比較器。
我用於實現Comparable
和Comparator
注釋庫:
public class Person implements Comparable<Person> {
private String firstName;
private String lastName;
private int age;
private char gentle;
@Override
@CompaProperties({ @CompaProperty(property = "lastName"),
@CompaProperty(property = "age", order = Order.DSC) })
public int compareTo(Person person) {
return Compamatic.doComparasion(this, person);
}
}
單擊鏈接以查看更多示例。 http://code.google.com/p/compamatic/wiki/CompamaticByExamples
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.