Khi nào sử dụng So sánh và So sánh


108

Tôi có một danh sách các đối tượng mà tôi cần sắp xếp trên một trường, chẳng hạn như Điểm. Không cần suy nghĩ nhiều, tôi đã viết một lớp mới thực hiện Comparator, nó thực hiện nhiệm vụ và nó hoạt động.

Bây giờ nhìn lại điều này, tôi đang tự hỏi liệu thay vào đó tôi có nên để lớp của mình triển khai Comp Compare thay vì tạo một lớp mới thực hiện Comparator. Điểm số là trường duy nhất mà các đối tượng sẽ được sắp xếp.

  1. Những gì tôi đã làm được chấp nhận như một thông lệ?

  2. Có phải cách tiếp cận đúng "Đầu tiên có lớp triển khai So sánh (đối với thứ tự tự nhiên) và nếu cần so sánh trường thay thế, sau đó tạo một lớp mới triển khai Trình so sánh"?

  3. Nếu (2) ở trên là đúng, thì có nghĩa là người ta chỉ nên triển khai Comparator sau khi họ có lớp triển khai Comp Compare? (Giả sử tôi sở hữu lớp gốc).

Câu trả lời:


80

Tôi sẽ nói rằng một đối tượng nên triển khai So sánh nếu đó là cách tự nhiên rõ ràng để sắp xếp lớp và bất kỳ ai cần sắp xếp lớp nói chung sẽ muốn làm theo cách đó.

Tuy nhiên, nếu việc sắp xếp là một cách sử dụng không bình thường của lớp hoặc việc sắp xếp chỉ có ý nghĩa đối với một trường hợp sử dụng cụ thể, thì Bộ so sánh là một lựa chọn tốt hơn.

Nói một cách khác, với tên lớp, có rõ ràng là một so sánh sẽ sắp xếp như thế nào không, hay bạn phải dùng đến cách đọc javadoc? Nếu là trường hợp thứ hai, tỷ lệ cược là mọi trường hợp sử dụng sắp xếp trong tương lai sẽ yêu cầu một trình so sánh, tại thời điểm đó, việc triển khai so sánh có thể làm chậm người dùng của lớp chứ không phải tăng tốc độ của họ.


Bạn có thể vui lòng cho một ví dụ nhanh chóng?
rgamber

đây có thể là ví dụ tốt: gist.github.com/yclian/2627608 Có lớp Phiên bản sử dụng Comp CompareVersion . Phiên bản - cung cấp các phương thức ban đầu Comp CompareVersion được cho là đối tượng (không có phương thức tĩnh) - cung cấp một phiên bản có thể so sánh với một phiên bản khác. Các trách nhiệm được tách biệt.
ses

2
bạn có thể tham khảo java-journal.blogspot.in/2011/01/…
a Learner

Người phỏng vấn hỏi, tại sao sử dụng Comparator khi tương tự có thể được thực hiện với tính năng tương đương, và tôi đã câm :(
Aadam

Liên kết @aLearner đã chết
G.Brown

127

Sử dụng Comparablenếu bạn muốn xác định hành vi sắp xếp mặc định (tự nhiên) của đối tượng được đề cập, một thực tế phổ biến là sử dụng mã định danh kỹ thuật hoặc tự nhiên (cơ sở dữ liệu?) Của đối tượng cho việc này.

Sử dụng Comparatornếu bạn muốn xác định một hành vi đặt hàng có thể kiểm soát bên ngoài , điều này có thể ghi đè hành vi đặt hàng mặc định.


3
Đó là một lời giải thích kỹ thuật và đúng như những gì họ đưa ra, nhưng nó không thực sự nói gì về các phương pháp hay nhất.
extraneon vào

40
nó cho biết khi nào sử dụng từng cái - nếu đó không phải là phương pháp hay nhất, thì đó là gì?
Bozho

1
"Việc triển khai Comparablecó nghĩa là tôi đang xác định trật tự tự nhiên không?" , điều này đã cho tôi câu trả lời mà tôi đang tìm kiếm. Cảm ơn :)
Somjit 21/09/13

61

Sử dụng Comparable:

  • nếu đối tượng nằm trong tầm kiểm soát của bạn.
  • nếu hành vi so sánh là hành vi so sánh chính.

Sử dụng Comparator:

  • nếu đối tượng nằm ngoài tầm kiểm soát của bạn và bạn không thể khiến chúng thực hiện Comparable.
  • khi bạn muốn so sánh hành vi khác với hành vi mặc định (được chỉ định bởi Comparable).

20

Có thể so sánh -java.lang.Comparable: int compareTo(Object o1)

Một đối tượng có thể so sánh có khả năng so sánh chính nó với một đối tượng khác. Bản thân lớp phải triển khai giao diện java.lang.Comp so sánh được để có thể so sánh các thể hiện của nó.

  • Có khả năng so sánh đối tượng hiện tại với đối tượng được cung cấp.
  • Bằng cách sử dụng điều này, chúng tôi có thể triển khai only one sort sequencedựa trên các thuộc tính của phiên bản. VÍ DỤ:Person.id
  • Một số Class được xác định trước như String, Wrapper class, Date, Calendar đã triển khai giao diện So sánh.

Bộ so sánh -java.util.Comparator: int compare(Object o1, Object o2)

Đối tượng so sánh có khả năng so sánh hai đối tượng khác nhau. Lớp không so sánh các cá thể của nó, mà là một số cá thể của lớp khác. Lớp so sánh này phải triển khai giao diện java.util.Comparator.

  • Có khả năng so sánh bất kỳ hai Đối tượng Cùng Loại nào.
  • Bằng cách sử dụng điều này, chúng tôi có thể triển khai many sort sequencevà đặt tên cho mỗi cái, dựa trên các thuộc tính của phiên bản. VÍ DỤ:Person.id, Person.name, Person.age
  • Chúng tôi có thể triển khai giao diện Bộ so sánh cho các lớp được xác định trước của chúng tôi để sắp xếp Tùy chỉnh.

Thí dụ:

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)
    }
}
  • Đối với phân loại tùy chỉnh, chúng tôi sử dụng trình so sánh @compare (o1, o2) đối với các trường hợp khác, chúng tôi sử dụng @compareTo có thể so sánh (o1), không cần thay đổi mã nếu chúng tôi muốn sắp xếp nhiều trường thì chúng tôi sử dụng trình so sánh.

Đối với Java 8 Lambda: Tham khảo bộ so sánh trong bài đăng của tôi.


10

So sánh nên được sử dụng khi bạn so sánh các cá thể của cùng một lớp.

Bộ so sánh có thể được sử dụng để so sánh các cá thể của các lớp khác nhau.

So sánh được thực hiện bởi lớp cần xác định thứ tự tự nhiên cho các đối tượng của nó. Giống như chuỗi thực hiện có thể so sánh được.

Trong trường hợp một người muốn một thứ tự sắp xếp khác thì anh ta có thể triển khai trình so sánh và xác định cách riêng của nó để so sánh hai trường hợp.


10

Nếu việc sắp xếp các đối tượng cần dựa trên thứ tự tự nhiên thì hãy sử dụng So sánh trong khi nếu việc sắp xếp của bạn cần được thực hiện trên các thuộc tính của các đối tượng khác nhau, thì hãy sử dụng Bộ so sánh trong Java.

Sự khác biệt chính giữa So sánh và So sánh:

+------------------------------------------------------------------------------------+
¦               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.        ¦
+------------------------------------------------------------------------------------+

9

Trình so sánh làm được mọi thứ mà tính năng so sánh làm được, và hơn thế nữa.

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

Tôi đã tìm thấy phương pháp tốt nhất để sử dụng trình so sánh dưới dạng các lớp ẩn danh như sau:

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());
        }
    });
}

Bạn có thể tạo nhiều phiên bản của các phương thức như vậy ngay trong lớp mà bạn định sắp xếp. Vì vậy, bạn có thể có:

  • sortAccountsByP Prete
  • sortAccountsByType
  • sortAccountsByPosystemAndType

    Vân vân...

Bây giờ, bạn có thể sử dụng các phương pháp sắp xếp này ở bất cứ đâu và sử dụng lại mã. Điều này mang lại cho tôi mọi thứ đều có thể so sánh được, cộng với nhiều hơn nữa ... vì vậy tôi không thấy có lý do gì để sử dụng so sánh cả.


8

Tôi sẽ nói:

  • nếu so sánh là trực quan, thì bằng mọi cách, hãy triển khai So sánh
  • nếu nó không rõ ràng hơn so sánh của bạn là trực quan, hãy sử dụng So sánh vì nó rõ ràng hơn và do đó rõ ràng hơn cho những người nghèo phải duy trì mã
  • nếu có thể có nhiều hơn một phép so sánh trực quan, tôi muốn một Bộ so sánh, có thể được xây dựng bằng phương pháp gốc trong lớp được so sánh.
  • nếu so sánh có mục đích đặc biệt, hãy sử dụng Bộ so sánh

6

Những điểm sau đây giúp bạn quyết định trong những tình huống nào nên sử dụng So sánh và trong đó So sánh:

1) Tính sẵn có của mã

2) Tiêu chí phân loại đơn so với nhiều tiêu chí

3) Arays.sort () và Collection.sort ()

4) Như các khóa trong SortedMap và SortedSet

5) Số lượng lớp học nhiều hơn so với tính linh hoạt

6) So sánh giữa các lớp

7) Thứ tự tự nhiên

Để có bài viết chi tiết hơn, bạn có thể tham khảo Khi nào sử dụng so sánh và khi nào sử dụng so sánh


Tôi tự hỏi tại sao không ai ủng hộ câu trả lời này. Đó là một trong những thực sự tốt đẹp. +1
Diganta

4
  • Nếu tại thời điểm viết lớp, bạn chỉ có một trường hợp sử dụng là sắp xếp sử dụng Có thể so sánh.
  • Chỉ khi bạn có nhiều hơn một chiến lược sắp xếp, hãy triển khai Bộ so sánh.

4

Nếu bạn cần sắp xếp thứ tự tự nhiên - Người dùng có thể so sánh NẾU bạn cần Sắp xếp thứ tự tùy chỉnh - Sử dụng công cụ so sánh

Thí dụ:

Class Employee{
private int id;
private String name;
private String department;
}

Thứ tự tự nhiên Sắp xếp sẽ dựa trên id vì nó sẽ là duy nhất và thứ tự tùy chỉnh sortin g sẽ là tên và phòng ban.

Refrences:
Khi nào một lớp nên là So sánh và / hoặc So sánh? http://javarevisited.blogspot.com/2011/06/comparator-and-compained-in-java.html


3

Đã có một câu hỏi tương tự ở đây: Khi nào một lớp nên là So sánh và / hoặc So sánh?

Tôi sẽ nói như sau: Triển khai Có thể so sánh cho thứ gì đó giống như thứ tự tự nhiên, ví dụ: dựa trên ID nội bộ

Triển khai Bộ so sánh nếu bạn có một thuật toán so sánh phức tạp hơn, ví dụ như nhiều trường, v.v.


1
Đặt hàng trên nhiều lĩnh vực có thể được thực hiện tốt với Comparable.
BalusC

Để biết sự khác biệt giữa bộ so sánh và bộ so sánh, bạn có thể tham khảo java-journal.blogspot.in/2010/12/…
a Learner

2

Có thể so sánh:
Bất cứ khi nào chúng ta chỉ muốn lưu trữ các phần tử thuần nhất và yêu cầu thứ tự sắp xếp tự nhiên mặc định, chúng ta có thể sử dụng comparablegiao diện triển khai lớp .

Bộ so sánh:
Bất cứ khi nào chúng ta muốn lưu trữ các phần tử đồng nhất và không đồng nhất và chúng ta muốn sắp xếp theo thứ tự sắp xếp tùy chỉnh mặc định, chúng ta có thể vào comparatorgiao diện.


0

Nhu cầu của tôi được sắp xếp dựa trên ngày tháng.

Vì vậy, tôi đã sử dụng So sánh và nó hoạt động dễ dàng đối với tôi.

public int compareTo(GoogleCalendarBean o) {
    // TODO Auto-generated method stub
    return eventdate.compareTo(o.getEventdate());
}

Một hạn chế với So sánh là chúng không thể sử dụng cho các Bộ sưu tập ngoài Danh sách.


0

Nếu bạn sở hữu lớp học tốt hơn hãy đi với So sánh . Nói chung Comparator được sử dụng nếu bạn không sở hữu lớp nhưng bạn phải sử dụng nó là TreeSet hoặc TreeMap vì Comparator có thể được truyền như một tham số trong conctructor của TreeSet hoặc TreeMap. Bạn có thể xem cách sử dụng So sánh và So sánh trong http://preciselyconcise.com/java/collections/g_comparator.php


0

Tôi đã được yêu cầu sắp xếp một loạt các số nhất định trong thời gian tốt hơn nlogn trong một cuộc phỏng vấn. (Không sử dụng sắp xếp đếm)

Việc triển khai giao diện So sánh trên một đối tượng cho phép các thuật toán sắp xếp ngầm sử dụng phương thức CompareTo bị ghi đè để sắp xếp các phần tử sắp xếp và đó sẽ là thời gian tuyến tính.


0

Có thể so sánh là thứ tự sắp xếp tự nhiên mặc định được cung cấp cho các giá trị số tăng dần và cho các chuỗi là thứ tự bảng chữ cái. ví dụ:

Treeset t=new Treeset();
t.add(2);
t.add(1);
System.out.println(t);//[1,2]

Bộ so sánh là thứ tự sắp xếp tùy chỉnh được triển khai trong lớp myComparator tùy chỉnh bằng cách ghi đè một phương thức so sánh cho ví dụ:

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]

-1

Cách tiếp cận rất đơn giản là giả sử rằng lớp thực thể được đề cập được biểu diễn trong cơ sở dữ liệu và sau đó trong bảng cơ sở dữ liệu, bạn có cần chỉ mục được tạo thành từ các trường của lớp thực thể không? Nếu câu trả lời là có thì hãy triển khai so sánh và sử dụng (các) trường chỉ mục cho thứ tự sắp xếp tự nhiên. Trong tất cả các trường hợp khác, hãy sử dụng bộ so sánh.


-2

Chú thích lib của tôi để triển khai 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);         
    }  
}

Nhấp vào liên kết để xem thêm ví dụ. http://code.google.com/p/compamatic/wiki/CompamaticByExamples

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.