เหตุใดคลาส Java จึงควรใช้การเทียบเคียง


139

ทำไมจึงComparableใช้Java ? ทำไมบางคนถึงใช้Comparableในชั้นเรียน อะไรคือตัวอย่างชีวิตจริงที่คุณต้องใช้เทียบเคียง?



มีตัวอย่างที่ดีที่นี่: java67.blogspot.com/2012/10/…
james.garriss

คำตอบ:


216

นี่คือตัวอย่างชีวิตจริง ทราบว่ายังมีการดำเนินการStringComparable

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

ต่อมา ..

/**
 * 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
ฉันแค่อยากจะทราบว่าบ่อยครั้งที่คุณต้องการลบล้างequals(ดังนั้นhashCode) เพื่อให้สอดคล้องกับcompareToวิธีการของคุณ ตัวอย่างเช่นสิ่งนี้จำเป็นหากคุณต้องการให้คลาสเล่นได้ดีกับไฟล์TreeSet.
pidge

ทำไมไม่กลับไปlast?
Anirban Nag 'tintinmj'

@ AnirbanNag'tintinmj 'เพื่อเรียงลำดับโดยอัตโนมัติตามชื่อในกรณีที่นามสกุลเหมือนกัน
OddDev

บวกหนึ่งสำหรับคำอธิบายที่ดีว่าทำไมจึงเปรียบเทียบถึงส่งคืน int และความหมาย เป็นประโยชน์ที่สุด
james.garriss

1
@ user3932000: ใช่แล้วนั่นคือจุดสำคัญของอินเทอร์เฟซทั้งหมด แต่โปรดทราบว่า "วิธีการอื่น ๆ ของ Java" รวมถึงวิธีการที่เขียนโดยผู้ใช้! อันที่จริงฉันอ้างว่าอินเทอร์เฟซส่วนใหญ่ถูกใช้โดยรหัสของผู้ใช้ ในฐานรหัสที่ใหญ่ขึ้น "ตัวเอง" จะกลายเป็น "คนอื่น" อย่างรวดเร็ว
Enno Shioji

41

การเทียบเคียงกำหนดลำดับตามธรรมชาติ สิ่งนี้หมายความว่าคุณกำลังกำหนดค่าเมื่อวัตถุหนึ่งควรถือว่าเป็น "น้อยกว่า" หรือ "มากกว่า"

สมมติว่าคุณมีจำนวนเต็มและคุณต้องการจัดเรียง มันง่ายมากแค่ใส่ไว้ในคอลเลกชั่นที่จัดเรียงไว้ใช่มั้ย?

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

แต่ตอนนี้สมมติว่าฉันมีวัตถุที่กำหนดเองบางอย่างซึ่งการเรียงลำดับเหมาะสมกับฉัน แต่ไม่ได้กำหนดไว้ สมมติว่าฉันมีข้อมูลที่แสดงเขตตามรหัสไปรษณีย์พร้อมความหนาแน่นของประชากรและฉันต้องการจัดเรียงตามความหนาแน่น:

public class District {
  String zipcode; 
  Double populationDensity;
}

ตอนนี้วิธีที่ง่ายที่สุดในการจัดเรียงคือการกำหนดลำดับตามธรรมชาติโดยใช้การเปรียบเทียบซึ่งหมายความว่ามีวิธีมาตรฐานที่กำหนดให้วัตถุเหล่านี้สั่งได้:

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

โปรดทราบว่าคุณสามารถทำสิ่งที่เทียบเท่าได้โดยการกำหนดตัวเปรียบเทียบ ความแตกต่างคือเปรียบเทียบกำหนดตรรกะการสั่งซื้อนอกวัตถุ บางทีในกระบวนการแยกต่างหากฉันจำเป็นต้องสั่งซื้อวัตถุเดียวกันด้วยรหัสไปรษณีย์ - ในกรณีนี้การสั่งซื้อไม่จำเป็นต้องเป็นคุณสมบัติของวัตถุหรือแตกต่างจากการเรียงลำดับตามธรรมชาติของวัตถุ คุณสามารถใช้ตัวเปรียบเทียบภายนอกเพื่อกำหนดการจัดลำดับที่กำหนดเองสำหรับจำนวนเต็มตัวอย่างเช่นโดยการจัดเรียงตามค่าตามตัวอักษร

โดยพื้นฐานแล้วตรรกะการสั่งซื้อจะต้องมีอยู่ที่ไหนสักแห่ง ที่สามารถ -

  • ในตัววัตถุเองถ้ามันเทียบเคียงได้ตามธรรมชาติ (ขยายจำนวนเต็ม Comparable -eg)

  • ให้มาในตัวเปรียบเทียบภายนอกดังตัวอย่างด้านบน


ตัวอย่างที่ดี แต่มันจะต้องมีTreeSet<Integer>แทนTreeMap<Integer>สำหรับหลังไม่อยู่ทรีแม็ปอยู่เสมอ<Key,Value>-pairs Btw สมมุติTreeMap<District, Object>จะใช้ได้ผลถ้า District ใช้ Comparable ใช่ไหม? ยังคงพยายามเข้าใจสิ่งนี้
phil294

14

ยกมาจาก javadoc;

อินเทอร์เฟซนี้กำหนดลำดับทั้งหมดบนอ็อบเจ็กต์ของแต่ละคลาสที่ใช้ การเรียงลำดับนี้เรียกว่าการจัดลำดับตามธรรมชาติของคลาสและวิธีการ CompareTo ของคลาสจะเรียกว่าวิธีการเปรียบเทียบตามธรรมชาติ

รายการ (และอาร์เรย์) ของอ็อบเจ็กต์ที่ใช้อินเทอร์เฟซนี้สามารถจัดเรียงโดยอัตโนมัติโดย Collections.sort (และ Arrays.sort) ออบเจ็กต์ที่ใช้อินเทอร์เฟซนี้สามารถใช้เป็นคีย์ในแผนที่ที่เรียงลำดับหรือเป็นองค์ประกอบในชุดที่เรียงลำดับได้โดยไม่จำเป็นต้องระบุตัวเปรียบเทียบ

แก้ไข: .. และทำให้บิตที่สำคัญเป็นตัวหนา


4
ฉันจะบอกว่าประโยคหลังประโยคที่คุณเป็นตัวหนานั้นสำคัญ (ถ้าไม่มากกว่านั้น)
Michael Borgwardt

9

ความจริงที่ว่าคลาสใช้Comparableหมายความว่าคุณสามารถนำวัตถุสองชิ้นจากคลาสนั้นมาเปรียบเทียบกันได้ บางคลาสเช่นคอลเลกชันบางอย่าง (ฟังก์ชันการจัดเรียงในคอลเล็กชัน) ที่เก็บอ็อบเจ็กต์ตามลำดับโดยอาศัยการเทียบเคียงกัน (ในการจัดเรียงคุณจำเป็นต้องทราบว่าอ็อบเจ็กต์ใด "ใหญ่ที่สุด" และอื่น ๆ )


8

ตัวอย่างส่วนใหญ่ด้านบนแสดงวิธีการนำวัตถุเทียบเคียงที่มีอยู่กลับมาใช้ใหม่ในฟังก์ชัน CompareTo หากคุณต้องการใช้การเปรียบเทียบของคุณเองเมื่อคุณต้องการเปรียบเทียบวัตถุสองชิ้นที่มีคลาสเดียวกันให้พูดว่าออบเจ็กต์ AirlineTicket ที่คุณต้องการจัดเรียงตามราคา (น้อยกว่าคืออันดับแรก) ตามด้วยจำนวนจุดแวะพัก (อีกครั้งน้อยกว่าคือ อันดับแรก) คุณจะทำสิ่งต่อไปนี้:

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

วิธีง่ายๆในการใช้การเปรียบเทียบหลายฟิลด์คือการใช้ComparisonChain ของ Guavaจากนั้นคุณสามารถพูดได้

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

แทน

  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

การเปรียบเทียบใช้เพื่อเปรียบเทียบอินสแตนซ์ของชั้นเรียนของคุณ เราสามารถเปรียบเทียบอินสแตนซ์จากหลาย ๆ วิธีนั่นคือเหตุผลที่เราต้องใช้วิธีการcompareToเพื่อที่จะรู้ว่า (คุณลักษณะ) ที่เราต้องการเปรียบเทียบอินสแตนซ์อย่างไร

Dog ชั้น:

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 ชั้น:

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

    }
}

นี่คือตัวอย่างที่ดีในการใช้งานเทียบเท่าใน Java:

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


3

ตัวอย่างเช่นเมื่อคุณต้องการมีคอลเล็กชันหรือแผนที่ที่จัดเรียงไว้


สิ่งที่เฟอร์นันโดหมายถึงคือ: ถ้าคุณจัดเก็บ "สิ่งของ" ที่ใช้การเปรียบเทียบได้ในคลาสคอนเทนเนอร์ที่เรียงลำดับคลาสคอนเทนเนอร์ที่เรียงลำดับจะสามารถสั่งซื้อ "สิ่งของ" เหล่านั้นโดยอัตโนมัติ
Ian Durkan

2

เมื่อคุณใช้อินเตอร์เฟซที่คุณจะต้องใช้วิธีการComparable compareTo()คุณต้องใช้เพื่อเปรียบเทียบวัตถุเพื่อใช้ตัวอย่างเช่นวิธีการเรียงลำดับของArrayListคลาส คุณต้องการวิธีเปรียบเทียบวัตถุของคุณเพื่อให้สามารถจัดเรียงได้ ดังนั้นคุณต้องมีcompareTo()วิธีการที่กำหนดเองในชั้นเรียนของคุณเพื่อให้คุณสามารถใช้กับArrayListวิธีการจัดเรียงได้ compareTo()วิธีการส่งกลับ -1,0,1

ฉันเพิ่งอ่านบทตามใน Java Head 2.0 ฉันยังคงเรียนรู้


1

ตกลง แต่ทำไมไม่เพียงกำหนดcompareTo()วิธีการโดยไม่ใช้อินเทอร์เฟซที่เทียบเคียงได้ ตัวอย่างเช่นคลาสที่Cityกำหนดโดยnameและtemperatureและ

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

วิธีนี้ใช้ไม่ได้ โดยไม่ต้องใช้การเทียบเคียง - ฉันได้รับข้อยกเว้นคลาสคาสต์
Karan Ahuja
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.