2013-08-31 57 views
4

「您將如何按員工ID或姓名對員工對象進行排序」。爲此,我們可以使用兩個接口,即Comparator and Comparable. 看來這是對常見的面試問題比較器優於比較器的方式是什麼?

之一,但我不明白爲什麼我應該使用這兩種排序Employee對象

我一直在想一個理由comparator做什麼Comparable不能做。 我知道如果對象(比較的實例變量)有自然排序,那麼comparable是正確的選擇。 但如果需要自定義排序(例如字符串長度),那麼可以編寫一個comparator. 我的觀點是comparator只有客戶端需要,如果他想按照其他條件對數據進行排序。 例如,我將實施Employee class,使用comparable interfaceid排序。 ,但如果客戶想按String(姓名)對Employee對象進行排序,他將實現comparator作爲具體類或匿名排序。 有什麼我在這裏失蹤?

例如,在以下代碼中,對於Person對象,我的compareTo方法比較了年齡並對其進行了排序 在比較方法中,我使用字符串長度(人的姓名)進行排序。理論上,我可以在compareTo方法中完成這兩個操作,正如我在下面實現的那樣。

最後,還有我在兩種方式 1.作爲在主方法註釋掉 2.如匿名對象(?)的靜態方法來實現比較器下面的優於其他 中的一個的任何額外的好處這被註釋掉 3.實現比較新的類並調用類的實例中collections.sort() - 這個我沒有在這裏做

(The commented-out parts of the code works. They are just different implementations) 

mport java.util.Collections; 
import java.util.Comparator; 
import java.util.*; 

public class PersonComparator implements Comparable{ 
    private String name; 
    private int age; 

    public PersonComparator(String name, int age) { 
     this.name = name; 
     this.age = age; 
    } 
@Override 
public String toString() { 
    return "name=" + name + ", age=" + age; 
} 

/*@Override 
public int compareTo(Object obj) { 
    if (!(obj instanceof PersonComparator)) { 
     throw new ClassCastException("Invalid object"); 
    } 
    PersonComparator p2 = (PersonComparator)obj; 
    return this.age-p2.age; 
}*/ 

/*Alternative CompareTo that checks for both age and name*/ 
public int compareTo(Object obj) { 
    if (!(obj instanceof PersonComparator)) { 
     throw new ClassCastException("Invalid object"); 
    } 
    PersonComparator p2 = (PersonComparator)obj; 
    if (this.age!=p2.age){ 
     return this.age-p2.age; 
    } 
    else { 
    return (this.name.length()-p2.name.length()); 
} 
} 


/*public static Comparator nameLengthComparator 
= new Comparator() { 


    @Override 
    public int compare(Object obj1, Object obj2) { 
     if (!(obj1 instanceof PersonComparator) || !(obj2 instanceof PersonComparator)){ 
      throw new ClassCastException("Invalid object"); 
     } 
     else { 
      PersonComparator p1 = (PersonComparator)obj1; 
      PersonComparator p2 = (PersonComparator)obj2; 
      return p1.name.length()-p2.name.length(); 
     } 
} 
};*/ 

public static void main(String[] args){ 
    PersonComparator p1 = new PersonComparator("Alexander", 45); 
    PersonComparator p2 = new PersonComparator("Pat", 27); 
    PersonComparator p3 = new PersonComparator("Zacky", 45); 
    PersonComparator p4 = new PersonComparator("Rake", 34); 

    List<PersonComparator> list = new ArrayList<PersonComparator>(); 
    list.add(p1); 
    list.add(p2); 
    list.add(p3); 
    list.add(p4); 

    System.out.println("Before sorting "+ list); 
    Collections.sort(list); 
    //System.out.println("After sorting by age "+ list); 
    //System.out.println("Before sorting "+ list); 
    //Collections.sort(list, nameLengthComparator); 
    System.out.println("After sorting by name length "+ list); 
    /*Collections.sort(list, new Comparator<PersonComparator>() { 
     @Override 
      public int compare(PersonComparator p1, PersonComparator p2) { 
        return p1.name.length()-p2.name.length(); 
       } 
     } 
    );*/ 
    System.out.println("After sorting by name length "+ list); 
} 

} 

感謝

+0

是你說什麼... btw使用'可比較的'與泛型是類型安全的,而不是使用'Object' – nachokk

+0

使用Comparable接口可以爲一個類的對象定義單個排序順序。 比較器接口用於爲類的對象定義多個排序順序。 – Sanchit

回答

5

可比接口:

Comparable接口定義了一個Type的自然排序。假設您有一個字符串或整數列表,您可以將該列表傳遞給

Collections.sort(list);

,你將有一個排序的列表。怎麼樣?因爲字符串和整數都實現可比接口和可比接口的實現提供一個自然排序。它像類定義的說法 - 的compareTo「方法‘’如果你發現我喜歡的類型的對象的集合,根據我在定義的策略命令他們」。

現在,當你定義自己的類型,你可以通過實現可比接口定義你的類的對象的自然排序Here你會發現更多關於對象排序的信息。

比較接口

比較接口定義使用它你可以寫爲對象排序您的自定義策略「策略」界面。假設我們有如下一個簡單的「人」型:

public class Person { 
    String name; 

    public Person(String name) { 
     this.name = name; 
    } 

    public String getName() { 
     return name; 
    } 
} 

現在通過實施比較接口你可以寫不同的策略,爲了你的「人」類型的實例。例如,考慮人排序的以下兩項戰略:

class StartegyOne implements Comparator<Person> { 

    @Override 
    public int compare(Person p1, Person p2) { 
     return p1.getName().length() - p2.getName().length(); 
    } 

} 

class StartegyTwo implements Comparator<Person> { 

    @Override 
    public int compare(Person p1, Person p2) { 
     return p1.getName().compareTo(p2.getName()); 
    } 

} 

這裏戰略「全球信任度調查報告」訂貨會根據他們的名字的長度的人和「StrategyTwo」訂貨會的人基於詞典他們的名字排序。

實施比較的方式:

正如你所看到的,具體的策略類無國籍,因此所有實例在功能上等同。所以,我們只需要一個具體策略類的單個實例。因此,它應該是一個單例。每次執行調用時,使用匿名類將創建一個新實例。 考慮將對象存儲在私有靜態最終字段中,並通過使用靜態工廠方法訪問它們來重複使用它。。例如,您可以重新爲低於上述兩個具體策略:

class Strategies { 
private static final Comparator<Person> 
PERSON_NAME_LENGTH_COMPARATOR = new StartegyOne(); 

private static final Comparator<Person> 
PERSON_NAME_LEXICAL_COMPARATOR = new StartegyTwo(); 

public static Comparator<Person> personNameLengthComparator(){ 
    return PERSON_NAME_LENGTH_COMPARATOR; 
} 


public static Comparator<Person> personNameLexicalComparator(){ 
    return PERSON_NAME_LEXICAL_COMPARATOR; 
} 
} 

總之,可比接口用來定義一個類並比較接口的自然順序被用來定義對象的策略排序。

+1

「考慮將對象存儲在私有靜態最終字段中,並通過使用靜態工廠方法訪問它們」 - 好點,遵循由Joshua Bloch編寫的「有效Java」的指導原則 –

+0

「你可以看到,具體的策略類是無狀態的,因此所有的實例在功能上都是等價的。「 –

+0

@ user1988876:我們不在戰略課上維護任何狀態,因此他們是無國籍的。 'compare'方法的返回值取決於傳遞給它的參數值,它的操作不依賴於對象的**狀態**,因爲它沒有任何內容。我們的策略中有多少對象並不重要我們正在創建的類,它們的「比較」方法將爲同一組參數返回相同的值。因此我們可以說**無狀態類在功能上總是等價的**。 –

7

以何種方式比較優於比較?

這不是「優越」。只是這兩個接口以不同的方式完成(大致)相同的事情。在Comparable的情況下,排序邏輯位於被排序的對象中。在Comparator的情況下,邏輯與正在聲明的對象位於不同的類中。

但我不明白了一個道理,爲什麼我應該分揀員工同時使用對象

哪裏會是有意義的使用是,如果你需要的是能的唯一情況將對象排序爲不同的順序。然後,您可以宣佈相關類爲「自然」訂單實施Comparable,並使用Comparator對象來實施其他訂單。

順便說一下,比較器可能不應該實現Comparable,反之亦然。

如果比較實現Comparable暗示你想訂購的比較對象本身的情況下...

PersonComparator類名不副實。它應該真的叫做Person


你能否澄清一件事在你的答案,我們從那麼Object類已經equals()方法爲什麼Comparator接口再次促進equals()方法?

數點:

  • 你似乎仍然是混亂的ComparableComparator目的。 Comparator對象上的equals方法將比較器與其他比較器進行比較!

  • equals方法告訴你兩個對象是否相等......不是哪個先來。

  • Comparator覆蓋equals使they can clearly document什麼equals(Object)確實,當你把它叫做Comparator對象上的原因。 (實際行爲與Object.equals(Object)完全一致......但他們顯然認爲有必要這麼做,因爲程序員們反覆得到方法錯誤的語義。)

+0

您能否在您的答案中澄清一件事,我們已經從Object類的equals()方法,然後爲什麼Comparator接口再次促進equals()方法? – Sanchit

+0

對於語句的+1 **可比較的**: - 「排序邏輯在對象本身的排序中」和在**比較器**中: - 「排序邏輯與待排序對象的類別不同」 – krohit

0

一般情況下,使用可比當排序「明顯」。例如,對於使用字母順序的字符串,對於使用數字順序的數字。請注意,Comparable對象只能實現單個compareTo()方法,因此您只能獲得一個選項 - 「自然」,「顯而易見」選項。優點是它很簡單,客戶端代碼不需要做任何額外的工作來比較事物。

如果排序不太明顯,或者您想要有多個選項,請使用比較器。例如,一本書可能會根據標題,作者,ISBN等進行排序。您可以使用三個不同的比較器來處理這三種情況。您可能想按某種不尋常的順序對字符串進行排序,例如一個外語的特殊情況,忽略首都,等等。

此外,如果你正在排序的對象沒有實現Comparable,或者你是混合類型不喜歡相互比較(通常,這是要避免,但也許您希望能夠在某些特殊情況下將書籍和作者比作一個列表),則需要使用Comparator。

+0

實際上,用字符串排序不一定很明顯。根據字符串代表什麼,至少有四種不同的方式可以合理地希望對「X4.9」,「X10.3」和「X4.12」進行排序。或者,就此而言,「你好」,「你好」和「嘿嘿」。 – supercat

4

比較器優於可比較的是什麼方式?

我不會說這是優越的,但一個優點是它使我們能夠編寫多個排序序列。在Comparable的情況下,您將不得不通過您想要排序的類實現該接口,並且只能編寫一個排序順序。

使用Comparator,您可以爲排序順序創建不同的類,並在排序時,只需將Comparator實例傳遞給COllections.sort()方法即可。

考慮Employee類,它有字段idfirstNamelastName。如果實現Comparable,您可以編寫只有一個compareTo方法排序邏輯。

如果實現Comparator那麼你可以通過創建單獨的類創建單獨的排序序列。例如IdSorterFirstNameSorterLastNameSorter,讓你的排序方式以多種方式Employee

Sorting user defined objects with Comparator

1

在這裏,你去...我已經寫了很多關於這個澄清的圖片和說明的幫助。

請查看以下鏈接:

Comparable and Comparator

一個認爲你可以永遠記住,這是 「他們不能互換使用」

3

媲美,您可以只基於一個field.Comparator提供了靈活性,基於多個字段

例如比較項目的集合項目進行排序。

class Person implements Comparable 
{ 

int age; 
String name; 


Person(int age,String name) 
{ 
    this.age=age; 
    this.name=name; 
} 

public int compareTo(Object o1) // Either you can compare according to age or name 
{ 
    Person p = (Person)o1; 
    if (this.age==p.age) 
    return 0; 
    else if (this.age>p.age) 
    return 1; 
    else 
    return -1; 
} 


public int compareTo(Object o) //Based on name comparision 
{ 
    return (this.name.compareTo((Person)o).name)); 
} 
public static void main (String args[]) 
{ 
    List<Person> list = new ArrayList<Person>(); 
    Person o = new Person(12,"Steve"); 
    Person o1 = new Person(13,"Jason"); 
    list.add(o); 
    list.add(o1); 
    Collections.sort(list); 
    } 
} 

在上述可比情況下,可以對項目進行排序或者使用年齡或name.But在比較的情況下,可以基於多個領域的項目進行排序。

class AgeComparison implements Comparator 
{ 
    public int compare(Object o1,Object o2) 
{ 
     Person s1 = (Person)o1; 
     Person s2 =(Person)o2; 
     if (s1.age==s2.age) 
     return 0; 
     if(s1.age>s2.age) 
     return 1; 
     else 
     return -1; 
} 

class NameComparison implements Comparator 
{ 
    public int compare(Object o1,Object o2) 
    { 
     Person s1 = (Person)o1; 
     Person s2 =(Person)o2; 
     return (s1.age.compareTo(s2.age)); 
    } 

} 

要使用比較器,您必須通過必須使用的類的列表和實例。

Collections.sort(list,new NameComparison()); 
Collections.sort(list,new AgeComparison()); 

概括地說,比較器的優點是能夠進行排序基於所述對象的多於一個字段的列表中的靈活性。

0

如果使用的是比較,你只需要使用List對象在現有的代碼中沒有其他變化而增加一個比較器類,並把它傳遞給Collections.sort()方法。

,但如果你實現可比的界面,你將不得不改變所有的模型/ bean類的代碼重寫的compareTo()方法。

所以鬆耦合比較好。