สวัสดี! วันนี้เราจะพูดถึงการเปรียบเทียบวัตถุ
อืม... แต่เราเคยพูดหัวข้อนี้มากกว่าหนึ่งครั้งไม่ใช่เหรอ? :/ เรารู้วิธี
ฉันควรใช้เมื่อใด
ตัวอย่างเช่น สมมติว่าเราต้องการจัดเรียงเช่นนี้ 15% ของเวลา เห็นได้ชัดว่าไม่เพียงพอสำหรับเราที่จะตั้งค่า

==
การทำงานของตัวดำเนินการตลอดจนequals()
วิธีhashCode()
การ การเปรียบเทียบแตกต่างกันเล็กน้อย ก่อนหน้านี้ เรามักจะหมายถึง "การตรวจสอบวัตถุเพื่อความเท่าเทียมกัน" แต่เหตุผลในการเปรียบเทียบวัตถุกันอาจแตกต่างไปจากเดิมอย่างสิ้นเชิง! สิ่งที่ชัดเจนที่สุดคือการเรียงลำดับ ฉันคิดว่าถ้าคุณได้รับคำสั่งให้จัดเรียงArrayList<>
ตัวเลขหรือสตริง คุณจะสามารถจัดการสิ่งนี้ได้โดยไม่มีปัญหา:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Main {
public static void main(String[] args) {
String name1 = "Masha";
String name2 = "Sasha";
String name3 = "Dasha";
List<String> names = new ArrayList<>();
names.add(name1);
names.add(name2);
names.add(name3);
Collections.sort(names);
System.out.println(names);
}
}
เอาต์พุตคอนโซล:
[Dasha, Masha, Sasha]
หากคุณจำCollections
คลาสและsort()
วิธีการของมันได้ ทำได้ดีมาก! ฉันคิดว่าคุณจะไม่มีปัญหากับตัวเลข นี่เป็นงานที่ท้าทายมากขึ้นสำหรับคุณ:
public class Car {
private int manufactureYear;
private String model;
private int maxSpeed;
public Car(int manufactureYear, String model, int maxSpeed) {
this.manufactureYear = manufactureYear;
this.model = model;
this.maxSpeed = maxSpeed;
}
// ...getters, setters, toString()
}
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Car> cars = new ArrayList<>();
Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
Car lambo = new Car(2012, "Lamborghini Gallardo", 290);
Car bugatti = new Car(2010, "Bugatti Veyron", 350);
cars.add(ferrari);
cars.add(bugatti);
cars.add(lambo);
}
}
งานเป็นเรื่องง่ายจริงๆ เรามีCar
วัตถุคลาสและ 3 รถยนต์ คุณช่วยเรียงลำดับรถในรายการได้ไหม? คุณอาจจะถามว่า "ควรจัดเรียงอย่างไร" โดยชื่อ? ตามปีที่ผลิต? ด้วยความเร็วสูงสุด? คำถามที่ยอดเยี่ยม ในขณะนี้ เราไม่ทราบวิธีการจัดเรียงCar
วัตถุ และโดยธรรมชาติแล้ว Java ก็ไม่รู้เหมือนกัน! เมื่อเราพยายามส่งรายการCar
วัตถุไปยังCollections.sort()
เมธอด เราได้รับข้อผิดพลาด:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Car> cars = new ArrayList<>();
Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
Car lambo = new Car(20012, "Lamborghini Gallardo", 290);
Car bugatti = new Car(2010, "Bugatti Veyron", 350);
cars.add(ferrari);
cars.add(bugatti);
cars.add(lambo);
// Compilation error!
Collections.sort(cars);
}
}
และภาษาจะรู้วิธีจัดเรียงวัตถุของชั้นเรียนที่คุณเขียนได้อย่างไร ขึ้นอยู่กับว่าโปรแกรมของคุณต้องการทำอะไร เราต้องสอน Java เพื่อเปรียบเทียบวัตถุเหล่านี้ และเพื่อเปรียบเทียบให้ตรงตามที่เราต้องการ Java มีกลไกพิเศษสำหรับสิ่งนี้: Comparable
อินเทอร์เฟซ ในการเปรียบเทียบและจัดเรียงCar
ออบเจกต์ของเรา คลาสจะต้องใช้อินเทอร์เฟซนี้ซึ่งประกอบด้วยเมธอดเดียว: compareTo()
:
public class Car implements Comparable<Car> {
private int manufactureYear;
private String model;
private int maxSpeed;
public Car(int manufactureYear, String model, int maxSpeed) {
this.manufactureYear = manufactureYear;
this.model = model;
this.maxSpeed = maxSpeed;
}
@Override
public int compareTo(Car o) {
return 0;
}
// ...getters, setters, toString()
}
โปรดทราบที่เราระบุComparable<Car>
อินเทอร์เฟซ ไม่ใช่แค่Comparable
. นี่คืออินเทอร์เฟซที่กำหนดพารามิเตอร์ นั่นคือเราต้องระบุคลาสที่เกี่ยวข้องเฉพาะ โดยหลักการแล้ว คุณสามารถลบออก<Car>
จากอินเทอร์เฟซได้ แต่การเปรียบเทียบจะยึดตามObject
วัตถุตามค่าเริ่มต้น แทนที่จะเป็นcompareTo(Car o)
เมธอด คลาสของเราจะมี:
@Override
public int compareTo(Object o) {
return 0;
}
แน่นอน มันง่ายกว่ามากสำหรับเราที่จะทำงานCar
ด้วย ภายในcompareTo()
วิธีการ เราใช้ตรรกะของเราในการเปรียบเทียบรถยนต์ สมมติว่าเราต้องจัดเรียงตามปีที่ผลิต คุณอาจสังเกตเห็นว่าcompareTo()
เมธอดส่งคืน an int
ไม่ใช่boolean
a อย่าปล่อยให้สิ่งนี้ทำให้คุณประหลาดใจ เมื่อเราเปรียบเทียบสองวัตถุ มีความเป็นไปได้ 3 ประการ:
а < b
a > b
a == b
.
boolean
มีค่าเพียง 2 ค่า: จริงและเท็จ ซึ่งใช้ไม่ได้ผลในการเปรียบเทียบวัตถุ ด้วยint
ทุกอย่างง่ายขึ้นมาก หากค่าที่ส่งกลับเป็น> 0
ดังนั้น a > b
ถ้าผลลัพธ์ของcompareTo
คือ< 0
แล้วa < b
. และถ้าผลลัพธ์คือ== 0
วัตถุสองชิ้นจะเท่ากันa == b
: การสอนชั้นเรียนของเราให้จัดเรียงรถยนต์ตามปีที่ผลิตนั้นง่ายมาก:
@Override
public int compareTo(Car o) {
return this.getManufactureYear() - o.getManufactureYear();
}
แต่เกิดอะไรขึ้นที่นี่? เรานำวัตถุรถยนต์หนึ่งชิ้น ( this
) รับปีที่ผลิตของรถคันนี้ และลบด้วยปีที่ผลิตของรถยนต์อีกคันหนึ่ง หากปีที่ผลิตรถยนต์คันแรกมากกว่า วิธีนี้จะคืนค่าint > 0
เป็น ซึ่ง หมายความว่าthis car >
รถยนต์ o
ในทางกลับกัน หากปีที่ผลิตรถยนต์คันที่สอง ( о
) มากกว่า วิธีการจะส่งกลับเป็นจำนวนลบ ซึ่งหมายความo > this
ว่า สุดท้ายหากเท่ากัน วิธีการจะคืน0
ค่า กลไกง่ายๆ นี้เพียงพอแล้วสำหรับเราในการจัดเรียงคอลเลกชันของCar
วัตถุ! คุณไม่ต้องทำอะไรอีก ตรวจสอบออก:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Car> cars = new ArrayList<>();
Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
Car lambo = new Car(2012, "Lamborghini Gallardo", 290);
Car bugatti = new Car(2010, "Bugatti Veyron", 350);
cars.add(ferrari);
cars.add(bugatti);
cars.add(lambo);
// There was previously an error here
Collections.sort(cars);
System.out.println(cars);
}
}
เอาต์พุตคอนโซล:
[Car{manufactureYear=1990, model='Ferrari 360 Spider', maxSpeed=310},
Car{manufactureYear=2010, model='Bugatti Veyron', maxSpeed=350},
Car{manufactureYear=2012, model='Lamborghini Gallardo', maxSpeed=290}]
รถเรียงตามที่เราต้องการ! :) 
Comparable
? วิธีการเปรียบเทียบที่ใช้Comparable
เรียกว่าลำดับตามธรรมชาติ นี่เป็นเพราะในcompareTo()
วิธีการที่คุณกำหนดวิธีการเปรียบเทียบวัตถุของคลาสนี้โดยทั่วไปหรือเป็นธรรมชาติที่สุด Java มีลำดับตามธรรมชาติอยู่แล้ว ตัวอย่างเช่น Java รู้ว่าสตริงมักจะถูกจัดเรียงตามตัวอักษร และตัวเลขโดยการเพิ่มค่าตัวเลข ดังนั้น หากคุณเรียกsort()
ใช้เมธอดในรายการของตัวเลขหรือสตริง พวกมันจะถูกจัดเรียง หากโปรแกรมของเรามักจะเปรียบเทียบและจัดเรียงรถยนต์ตามปีที่ผลิต เราควรกำหนดการจัดเรียงตามธรรมชาติสำหรับรถยนต์โดยใช้อินComparable<Car>
เทอร์เฟซและcompareTo()
วิธี. แต่ถ้ามันไม่เพียงพอสำหรับเราล่ะ ลองจินตนาการว่าโปรแกรมของเราไม่ง่ายนัก ในกรณีส่วนใหญ่ การจัดเรียงตามธรรมชาติของรถยนต์ (ซึ่งเรากำหนดให้ดำเนินการตามปีที่ผลิต) เหมาะสมกับเรา แต่บางครั้งลูกค้าของเราก็ชื่นชอบการขับรถเร็ว หากเรากำลังเตรียมแคตตาล็อกรถให้พวกเขาอ่าน ควรจัดเรียงรถด้วยความเร็วสูงสุด 
Car
การจัดเรียงตามธรรมชาติของคลาสเป็นตามความเร็วแทนที่จะเป็นปีที่ผลิต แต่เราไม่สามารถเพิกเฉยต่อลูกค้า 15% ของเราได้ ดังนั้นสิ่งที่เราจะทำ? อินเทอร์เฟซอื่นมาช่วยเราที่นี่: Comparator
. เช่นเดียวกับComparable
มันเป็นอินเทอร์เฟซแบบกำหนดพารามิเตอร์ ความแตกต่างคืออะไร? Comparable
ทำให้วัตถุของเรา "เปรียบเทียบได้" และกำหนดลำดับการจัดเรียงที่เป็นธรรมชาติที่สุด นั่นคือลำดับการจัดเรียงที่จะใช้ในกรณีส่วนใหญ่ Comparator
เป็นอินเทอร์เฟซ "เปรียบเทียบ" ที่แยกต่างหาก หากเราจำเป็นต้องใช้ลำดับการจัดเรียงแบบพิเศษ เราไม่จำเป็นต้องเข้าไปในคลาสCar
และเปลี่ยนตรรกะของcompareTo()
. แต่เราสามารถสร้างคลาสแยกต่างหากที่ใช้ Comparator และสอนวิธีดำเนินการเรียงลำดับที่เราต้องการได้!
import java.util.Comparator;
public class MaxSpeedCarComparator implements Comparator<Car> {
@Override
public int compare(Car o1, Car o2) {
return o1.getMaxSpeed() - o2.getMaxSpeed();
}
}
อย่างที่คุณเห็น ของเราComparator
ค่อนข้างเรียบง่าย เราจำเป็นต้องใช้วิธีอินเทอร์เฟซเดียวเท่านั้น: compare()
. ใช้Car
วัตถุสองชิ้นเป็นอินพุตและเปรียบเทียบความเร็วสูงสุดด้วยวิธีปกติ (โดยการลบ) เช่นเดียวกับcompareTo()
จะส่งกลับ an int
และหลักการเปรียบเทียบเหมือนกัน เราจะใช้สิ่งนี้อย่างไร ทุกอย่างตรงไปตรงมา:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Car> cars = new ArrayList<>();
Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
Car lambo = new Car(2012, "Lamborghini Gallardo", 290);
Car bugatti = new Car(2010, "Bugatti Veyron", 350);
cars.add(ferrari);
cars.add(bugatti);
cars.add(lambo);
Comparator speedComparator = new MaxSpeedCarComparator();
Collections.sort(cars, speedComparator);
System.out.println(cars);
}
}
เอาต์พุตคอนโซล:
[Car{manufactureYear=2012, model='Lamborghini Gallardo', maxSpeed=290},
Car{manufactureYear=1990, model='Ferrari 360 Spider', maxSpeed=310},
Car{manufactureYear=2010, model='Bugatti Veyron', maxSpeed=350}]
เราเพียงแค่สร้างวัตถุเปรียบเทียบและส่งต่อไปยังCollections.sort()
วิธีการพร้อมกับรายการที่จะจัดเรียง เมื่อsort()
เมธอดได้รับตัวเปรียบเทียบ จะไม่ใช้การเรียงลำดับตามธรรมชาติที่กำหนดไว้ในเมธอดCar
ของคลาส compareTo()
แต่จะใช้อัลกอริธึมการเรียงลำดับที่กำหนดโดยตัวเปรียบเทียบที่ส่งผ่านไปแทน ข้อดีของการทำเช่นนี้คืออะไร? ประการแรก ความเข้ากันได้กับรหัสที่มีอยู่ เราได้สร้างวิธีการคัดแยกแบบพิเศษขึ้นมาใหม่ โดยยังคงรักษาวิธีการคัดแยกที่มีอยู่ซึ่งจะใช้เวลาส่วนใหญ่ไว้ เราไม่ได้แตะCar
ชั้นเรียนเลย มันเป็นComparable
และมันก็ยังคงอยู่:
public class Car implements Comparable<Car> {
private int manufactureYear;
private String model;
private int maxSpeed;
public Car(int manufactureYear, String model, int maxSpeed) {
this.manufactureYear = manufactureYear;
this.model = model;
this.maxSpeed = maxSpeed;
}
@Override
public int compareTo(Car o) {
return this.getManufactureYear() - o.getManufactureYear();
}
// ...getters, setters, toString()
}
ประการที่สองความยืดหยุ่น เราสามารถเพิ่มอัลกอริทึมการเรียงลำดับได้มากเท่าที่เราต้องการ ตัวอย่างเช่น เราสามารถจัดเรียงรถตามสี ความเร็ว น้ำหนัก หรือจำนวนครั้งที่รถถูกใช้ในภาพยนตร์แบทแมน สิ่งที่เราต้องทำคือสร้างเพิ่มเติมComparator
. แค่นั้นแหละ! วันนี้ คุณได้ศึกษากลไกสำคัญสองอย่างที่คุณมักจะใช้ในโครงการจริงในที่ทำงาน แต่อย่างที่คุณทราบ ทฤษฎีที่ปราศจากการปฏิบัติก็ไร้ความหมาย ถึงเวลารวบรวมความรู้ของคุณและทำภารกิจให้สำเร็จ!
GO TO FULL VERSION