簡體   English   中英

何時使用 Comparable 和 Comparator

[英]When to use Comparable and Comparator

我有一個需要在字段上排序的對象列表,比如 Score。 我沒有多想就寫了一個實現 Comparator 的新類,它可以完成任務並且可以工作。

現在回想起來,我想知道我是否應該讓我的類實現 Comparable,而不是創建一個實現 Comparator 的新類。 分數是唯一可以對對象進行排序的字段。

  1. 我做了什么可以接受的做法?

  2. 正確的方法是“首先讓類實現 Comparable(用於自然排序),如果需要替代字段比較,然后創建一個實現 Comparator 的新類”?

  3. 如果上面的(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
  • 一些預定義類,如 String、Wrapper 類、Date、Calendar 已經實現了 Comparable 接口。

比較器- java.util.Comparator: int compare(Object o1, Object o2)

比較器對象能夠比較兩個不同的對象。 該類不是比較它的實例,而是比較其他一些類的實例。 這個比較器類必須實現 java.util.Comparator 接口。

  • 能夠比較任何兩個相同類型的對象。
  • 通過使用它,我們可以基於實例屬性實現many sort sequence並命名每個。 例如: Person.id, Person.name, Person.age
  • 我們可以為我們的預定義類實現 Comparator 接口以進行自定義排序。

例子:

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)
    }
}
  • 對於自定義排序,我們使用比較器 @compare(o1, o2) 對於其他場景,我們使用可比較的 @compareTo(o1),如果我們想要對多個字段進行排序,則無需更改代碼,然后我們使用比較器。

對於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

以下幾點可以幫助您決定在哪些情況下應該使用 Comparable 以及在哪種 Comparator 中使用:

1) 代碼可用性

2) 單與多排序標准

3) Arays.sort() 和 Collection.sort()

4) 作為 SortedMap 和 SortedSet 中的鍵

5)更多的類與靈活性

6) 類間比較

7) 自然秩序

有關更詳細的文章,您可以參考何時使用可比較以及何時使用比較器

  • 如果在編寫課程時您只有一個排序用例,請使用 Comparable。
  • 只有當您有多個排序策略時,才實施 Comparator。

如果您需要自然順序排序 - 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 一般比較使用,如果你不擁有一流的,但你必須使用一個TreeSetTreeMap的,因為比較可以在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]

非常簡單的方法是假設有問題的實體類在數據庫中表示,然后在數據庫表中您是否需要由實體類的字段組成的索引? 如果答案是肯定的,則實現可比較並使用索引字段進行自然排序。 在所有其他情況下使用比較器。

我用於實現ComparableComparator注釋庫:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM