Tại sao một lớp Java nên thực hiện so sánh?


136

Tại sao Java Comparableđược sử dụng? Tại sao ai đó sẽ thực hiện Comparabletrong một lớp học? Một ví dụ thực tế cuộc sống mà bạn cần phải thực hiện so sánh là gì?



Có một ví dụ điển hình ở đây: java67.blogspot.com/2012/10/ Cách
james.garriss 27/1/2016

Câu trả lời:


212

Đây là một mẫu thực tế cuộc sống. Lưu ý rằng Stringcũng thực hiện Comparable.

class Author implements Comparable<Author>{
    String firstName;
    String lastName;

    @Override
    public int compareTo(Author other){
        // compareTo should return < 0 if this is supposed to be
        // less than other, > 0 if this is supposed to be greater than 
        // other and 0 if they are supposed to be equal
        int last = this.lastName.compareTo(other.lastName);
        return last == 0 ? this.firstName.compareTo(other.firstName) : last;
    }
}

một lát sau..

/**
 * List the authors. Sort them by name so it will look good.
 */
public List<Author> listAuthors(){
    List<Author> authors = readAuthorsFromFileOrSomething();
    Collections.sort(authors);
    return authors;
}

/**
 * List unique authors. Sort them by name so it will look good.
 */
public SortedSet<Author> listUniqueAuthors(){
    List<Author> authors = readAuthorsFromFileOrSomething();
    return new TreeSet<Author>(authors);
}

15
Tôi chỉ muốn lưu ý rằng thường thì bạn sẽ muốn ghi đè equals(và do đó hashCode) để phù hợp với compareTophương pháp của bạn . Ví dụ, điều này là cần thiết nếu bạn muốn lớp chơi tốt với a TreeSet.
cháo

Tại sao không đơn giản trở lại last?
Anirban Nag 'tintinmj'

@ AnirbanNag'tintinmj 'để tự động sắp xếp theo tên trong trường hợp tên cuối cùng giống nhau.
OddDev

Thêm một cho lời giải thích tốt về lý do tại sao so sánh trả về một int và ý nghĩa của nó. Hữu ích nhất.
james.garriss

1
@ user3932000: Đúng vậy, đó là điểm chính của tất cả các giao diện. Nhưng lưu ý rằng "các phương thức Java khác" bao gồm các phương thức được viết bởi người dùng! Trong thực tế, tôi khẳng định phần lớn các giao diện được sử dụng bởi mã của người dùng. Trong các cơ sở mã lớn hơn, "chính bạn" nhanh chóng trở thành "người khác"
Enno Shioji

40

So sánh định nghĩa một trật tự tự nhiên. Điều này có nghĩa là bạn đang xác định nó khi một đối tượng nên được coi là "nhỏ hơn" hoặc "lớn hơn".

Giả sử bạn có một loạt các số nguyên và bạn muốn sắp xếp chúng. Điều đó khá dễ, chỉ cần đặt chúng vào một bộ sưu tập đã được sắp xếp, phải không?

TreeSet<Integer> m = new TreeSet<Integer>(); 
m.add(1);
m.add(3);
m.add(2);
for (Integer i : m)
... // values will be sorted

Nhưng bây giờ giả sử tôi có một số đối tượng tùy chỉnh, trong đó việc sắp xếp có ý nghĩa với tôi, nhưng không được xác định. Giả sử, tôi có dữ liệu đại diện cho các quận theo mã zip với mật độ dân số và tôi muốn sắp xếp chúng theo mật độ:

public class District {
  String zipcode; 
  Double populationDensity;
}

Bây giờ cách dễ nhất để sắp xếp chúng là xác định chúng theo thứ tự tự nhiên bằng cách thực hiện So sánh, có nghĩa là có một cách tiêu chuẩn mà các đối tượng này được xác định để được đặt hàng.:

public class District implements Comparable<District>{
  String zipcode; 
  Double populationDensity;
  public int compareTo(District other)
  {
    return populationDensity.compareTo(other.populationDensity);
  }
}

Lưu ý rằng bạn có thể làm điều tương tự bằng cách xác định một bộ so sánh. Sự khác biệt là bộ so sánh định nghĩa logic thứ tự bên ngoài đối tượng . Có thể trong một quy trình riêng biệt, tôi cần phải đặt hàng các đối tượng giống nhau bằng mã zip - trong trường hợp đó, thứ tự không nhất thiết phải là một thuộc tính của đối tượng hoặc khác với thứ tự tự nhiên của các đối tượng. Bạn có thể sử dụng một bộ so sánh bên ngoài để xác định thứ tự tùy chỉnh trên các số nguyên, ví dụ bằng cách sắp xếp chúng theo giá trị bảng chữ cái của chúng.

Về cơ bản logic đặt hàng phải tồn tại ở đâu đó. Đó có thể là -

  • trong chính đối tượng, nếu nó tự nhiên có thể so sánh được (mở rộng số nguyên so sánh -eg)

  • được cung cấp trong một bộ so sánh bên ngoài, như trong ví dụ trên.


ví dụ tốt, nhưng nó phải TreeSet<Integer>thay vì TreeMap<Integer>, vì cái sau không tồn tại, TreeMaps luôn luôn là <Key,Value>-pairs. Btw, một giả thuyết TreeMap<District, Object>sẽ chỉ hoạt động, nếu Quận thực hiện So sánh, phải không? Vẫn đang cố gắng để hiểu điều này
phil294

14

Trích dẫn từ javadoc;

Giao diện này áp đặt tổng thứ tự trên các đối tượng của mỗi lớp thực hiện nó. Thứ tự này được gọi là thứ tự tự nhiên của lớp và phương thức so sánh của lớp được gọi là phương thức so sánh tự nhiên của lớp.

Danh sách (và mảng) của các đối tượng thực hiện giao diện này có thể được sắp xếp tự động bởi Collections.sort (và Arrays.sort). Các đối tượng thực hiện giao diện này có thể được sử dụng làm khóa trong bản đồ được sắp xếp hoặc làm thành phần trong bộ được sắp xếp mà không cần chỉ định bộ so sánh.

Chỉnh sửa: .. và làm cho bit đậm quan trọng.


4
Tôi muốn nói rằng câu sau câu bạn đã in đậm cũng quan trọng không kém.
Michael Borgwardt

8

Thực tế là một lớp thực hiện Comparablecó nghĩa là bạn có thể lấy hai đối tượng từ lớp đó và so sánh chúng. Một số lớp, như các bộ sưu tập nhất định (chức năng sắp xếp trong một bộ sưu tập) giữ cho các đối tượng theo thứ tự dựa trên chúng có thể so sánh được (để sắp xếp bạn cần biết đối tượng nào là "lớn nhất" và vv).


8

Hầu hết các ví dụ trên cho thấy cách sử dụng lại một đối tượng có thể so sánh hiện có trong hàm so sánh. Nếu bạn muốn thực hiện so sánh của riêng mình khi bạn muốn so sánh hai đối tượng cùng loại, hãy nói một đối tượng AirlineTicket mà bạn muốn sắp xếp theo giá (ít được xếp hạng đầu tiên), tiếp theo là số lần dừng (một lần nữa, ít hơn là xếp thứ nhất), bạn sẽ làm như sau:

class AirlineTicket implements Comparable<Cost>
{
    public double cost;
    public int stopovers;
    public AirlineTicket(double cost, int stopovers)
    {
        this.cost = cost; this.stopovers = stopovers ;
    }

    public int compareTo(Cost o)
    {
        if(this.cost != o.cost)
          return Double.compare(this.cost, o.cost); //sorting in ascending order. 
        if(this.stopovers != o.stopovers)
          return this.stopovers - o.stopovers; //again, ascending but swap the two if you want descending
        return 0;            
    }
}

6

Một cách dễ dàng để thực hiện so sánh nhiều trường là với So sánh của Guava - sau đó bạn có thể nói

   public int compareTo(Foo that) {
     return ComparisonChain.start()
         .compare(lastName, that.lastName)
         .compare(firstName, that.firstName)
         .compare(zipCode, that.zipCode)
         .result();
   }

thay vì

  public int compareTo(Person other) {
    int cmp = lastName.compareTo(other.lastName);
    if (cmp != 0) {
      return cmp;
    }
    cmp = firstName.compareTo(other.firstName);
    if (cmp != 0) {
      return cmp;
    }
    return Integer.compare(zipCode, other.zipCode);
  }
}

3

Ví dụ: khi bạn muốn có một bộ sưu tập hoặc bản đồ được sắp xếp


Điều Fernando có nghĩa là: nếu bạn lưu trữ "những thứ" triển khai Có thể so sánh trong một lớp container được sắp xếp, lớp container được sắp xếp có thể tự động sắp xếp các "thứ" đó.
Ian Durkan

2

So sánh được sử dụng để so sánh các trường hợp của lớp học của bạn. Chúng ta có thể so sánh các thể hiện từ nhiều cách đó là lý do tại sao chúng ta cần triển khai một phương thức compareTođể biết cách (các thuộc tính) mà chúng ta muốn so sánh các thể hiện.

Dog lớp học:

package test;
import java.util.Arrays;

public class Main {

    public static void main(String[] args) {
        Dog d1 = new Dog("brutus");
        Dog d2 = new Dog("medor");
        Dog d3 = new Dog("ara");
        Dog[] dogs = new Dog[3];
        dogs[0] = d1;
        dogs[1] = d2;
        dogs[2] = d3;

        for (int i = 0; i < 3; i++) {
            System.out.println(dogs[i].getName());
        }
        /**
         * Output:
         * brutus
         * medor
         * ara
         */

        Arrays.sort(dogs, Dog.NameComparator);
        for (int i = 0; i < 3; i++) {
            System.out.println(dogs[i].getName());
        }
        /**
         * Output:
         * ara
         * medor
         * brutus
         */

    }
}

Main lớp học:

package test;

import java.util.Arrays;

public class Main {

    public static void main(String[] args) {
        Dog d1 = new Dog("brutus");
        Dog d2 = new Dog("medor");
        Dog d3 = new Dog("ara");
        Dog[] dogs = new Dog[3];
        dogs[0] = d1;
        dogs[1] = d2;
        dogs[2] = d3;

        for (int i = 0; i < 3; i++) {
            System.out.println(dogs[i].getName());
        }
        /**
         * Output:
         * brutus
         * medor
         * ara
         */

        Arrays.sort(dogs, Dog.NameComparator);
        for (int i = 0; i < 3; i++) {
            System.out.println(dogs[i].getName());
        }
        /**
         * Output:
         * ara
         * medor
         * brutus
         */

    }
}

Đây là một ví dụ tốt về cách sử dụng so sánh trong Java:

http://www.onjava.com/pub/a/onjava/2003/03/12/java_comp.html?page=2


2

Khi bạn thực hiện Comparablegiao diện, bạn cần thực hiện phương pháp compareTo(). Bạn cần nó để so sánh các đối tượng, để sử dụng, ví dụ, sắp xếp phương thức của ArrayListlớp. Bạn cần một cách để so sánh các đối tượng của bạn để có thể sắp xếp chúng. Vì vậy, bạn cần một compareTo()phương thức tùy chỉnh trong lớp để bạn có thể sử dụng nó với ArrayListphương thức sắp xếp. Các compareTo()trở về phương pháp -1,0,1.

Tôi vừa đọc một chương theo Java Head 2.0, tôi vẫn đang học.


1

OK, nhưng tại sao không chỉ định nghĩa một compareTo()phương thức mà không thực hiện giao diện so sánh. Ví dụ, một lớp Cityđược định nghĩa bởi nó nametemperature

public int compareTo(City theOther)
{
    if (this.temperature < theOther.temperature)
        return -1;
    else if (this.temperature > theOther.temperature)
        return 1;
    else
        return 0;
}

Điều này không hoạt động. Không thực hiện so sánh - tôi nhận được ngoại lệ classcast
Karan Ahuja
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.