JavaRush /จาวาบล็อก /Random-TH /เครื่องมือเปรียบเทียบใน Java

เครื่องมือเปรียบเทียบใน Java

เผยแพร่ในกลุ่ม
สวัสดี! วันนี้เราจะพูดถึงการเปรียบเทียบวัตถุ อืม... แต่ดูเหมือนเราจะคุยกันเรื่องนี้มากกว่าหนึ่งครั้งแล้วเหรอ? : / เรารู้ว่า==ตัวดำเนินการ “ ” ทำงานอย่างไร เช่นเดียวกับequals()and วิธีการ hashCode()การเปรียบเทียบไม่ได้เกี่ยวกับเรื่องนั้นจริงๆ ก่อนหน้านี้เราหมายถึง "การทดสอบวัตถุเพื่อความเท่าเทียมกัน" มากกว่า เครื่องมือเปรียบเทียบใน Java - 1แต่การเปรียบเทียบสิ่งของระหว่างกันอาจมีเป้าหมายที่แตกต่างกันโดยสิ้นเชิง! สิ่งที่ชัดเจนที่สุดคือการเรียงลำดับ ฉันคิดว่าถ้าคุณถูกบอกให้เรียงลำดับรายการ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 = "Даша";

       List<String> names = new ArrayList<>();
       names.add(name1);
       names.add(name2);
       names.add(name3);

       Collections.sort(names);
       System.out.println(names);
   }
}
เอาต์พุตคอนโซล:

[Даша, Маша, Саша]
จะดีมากถ้าคุณจำชั้นเรียน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;
   }

   //...геттеры, сеттеры, 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 ก็ไม่รู้เรื่องนี้เช่นกัน! เมื่อเราพยายามส่งCollections.sort()รายการวัตถุ ไปยัง method 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(20012, "Lamborghini Gallardo", 290);
       Car bugatti = new Car(2010, "Bugatti Veyron", 350);

       cars.add(ferrari);
       cars.add(bugatti);
       cars.add(lambo);

       //ошибка компилятора!
       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;
   }

   //...геттеры, сеттеры, toString()

}
ใส่ใจ:เราระบุอินเทอร์เฟซComparable<Car>ไม่ใช่แค่Comparable. นี่คืออินเทอร์เฟซแบบพิมพ์ กล่าวคือ จำเป็นต้องระบุคลาสเฉพาะที่เกี่ยวข้อง โดยหลักการแล้ว<Car>คุณสามารถลบออกจากอินเทอร์เฟซได้ แต่จะเปรียบเทียบวัตถุตามค่าเริ่มObjectต้น แทนที่จะเป็นวิธีการcompareTo(Car o)ในชั้นเรียนของเรา เราจะมี:
@Override
   public int compareTo(Object o) {
       return 0;
   }
แน่นอนว่า มันง่ายกว่ามากสำหรับเราที่จะทำงานร่วมCarกับ ภายในวิธีการcompareTo()ที่เราใช้ตรรกะในการเปรียบเทียบเครื่องจักร สมมติว่าเราต้องจัดเรียงตามปีที่ผลิต คุณ อาจสังเกตเห็นว่าวิธีการcompareTo()ส่งกลับค่าintไม่ใช่ booleanอย่าปล่อยให้สิ่งนี้ทำให้คุณประหลาดใจ ความจริงก็คือการเปรียบเทียบวัตถุสองชิ้นทำให้เรามีทางเลือกที่เป็นไปได้ 3 ทาง:
  • а < b
  • a > b
  • a == b.
มีbooleanเพียง 2 ค่าคือจริงและเท็จซึ่งไม่สะดวกในการเปรียบเทียบวัตถุ ทุกอย่างintง่ายกว่ามาก หากค่าที่ส่งคืนคือ> 0ดังนั้น a > bถ้าผลออกมาcompareTo < 0เป็นอย่างа < bนั้น ถ้าผลลัพธ์เป็น== 0แสดงว่าวัตถุทั้งสองมีค่าเท่ากันa == b: การสอนในชั้นเรียนของเราให้แยกประเภทรถยนต์ตามปีที่ผลิตนั้นง่ายพอๆ กับการปอกเปลือกลูกแพร์:
@Override
public int compareTo(Car o) {
   return this.getManufactureYear() - o.getManufactureYear();
}
เกิดอะไรขึ้นที่นี่? เราใช้วัตถุรถยนต์หนึ่งชิ้น ( this) ปีที่ผลิตรถคันนี้และลบปีที่ผลิตรถยนต์อีกคันออกจากมัน (อันที่เราเปรียบเทียบวัตถุ) หากปีที่ผลิตรถยนต์คันแรกมากกว่านั้น วิธีนี้จะคืนค่ากลับint > 0มา ซึ่งหมายถึงรถยนต์ ก็ คือthis >รถยนต์ оในทางกลับกัน หากปีที่ผลิตรถยนต์คันที่สอง ( о) มากกว่านั้น วิธีการก็จะส่งคืนตัวเลขที่เป็นลบ ดังนั้นо > 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);

       //тут раньше была ошибка
       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}]
รถถูกจัดเรียงตามที่ควรจะเป็น! :) เครื่องมือเปรียบเทียบใน Java - 2ควรใช้ในกรณีใดบ้างComparable? วิธีการเปรียบเทียบ ที่นำมาใช้Comparableเรียกว่า "การเรียงลำดับตามธรรมชาติ" เนื่องจากในวิธีการที่compareTo()คุณอธิบายวิธีการเปรียบเทียบที่พบบ่อยที่สุดที่จะใช้กับอ็อบเจ็กต์ของคลาสนี้ในโปรแกรมของคุณ Natural Ordering มีอยู่แล้วใน Java ตัวอย่างเช่น Java รู้ว่าสตริงมักเรียงลำดับตามตัวอักษร และตัวเลขมักเรียงลำดับตามค่าจากน้อยไปมาก ดังนั้น หากคุณเรียกใช้เมธอดในรายการตัวเลขหรือสตริงsort()ก็จะถูกจัดเรียง หากในโปรแกรมของเรา รถยนต์ส่วนใหญ่จะถูกเปรียบเทียบและจัดเรียงตามปีที่ผลิต ก็คุ้มค่าที่จะกำหนดการเรียงลำดับตามธรรมชาติโดยใช้อินเทอร์เฟซComparable<Car>และวิธีcompareTo()การ แต่ถ้านั่นยังไม่เพียงพอสำหรับเราล่ะ? ลองจินตนาการว่าโปรแกรมของเราไม่ง่ายนัก ในกรณีส่วนใหญ่ การคัดแยกรถยนต์ตามธรรมชาติ (เรากำหนดตามปีที่ผลิต) เหมาะกับเรา แต่บางครั้งในหมู่ลูกค้าของเราก็ชื่นชอบการขับรถเร็ว หากเรากำลังเตรียมแค็ตตาล็อกรถยนต์ให้เลือกจะต้องสั่งตามความเร็วสูงสุด เครื่องมือเปรียบเทียบใน Java - 3ตัวอย่างเช่น เราต้องการการเรียงลำดับดังกล่าวใน 15% ของกรณี เห็นได้ชัดว่านี่ไม่เพียงพอที่จะตั้งค่าการคัดแยกตามธรรมชาติCarตามความเร็วแทนที่จะเป็นปีที่ผลิต แต่เราไม่สามารถเพิกเฉยต่อลูกค้า 15% ได้ พวกเราทำอะไร? อินเทอร์เฟซอื่นมาช่วยเราที่นี่ - Comparator. เช่นเดียวกับที่Comparableมันถูกพิมพ์ ความแตกต่างคืออะไร? Comparableทำให้วัตถุของเรา "เปรียบเทียบได้" และสร้างลำดับการจัดเรียงที่เป็นธรรมชาติที่สุดสำหรับวัตถุเหล่านั้นซึ่งจะใช้ในกรณีส่วนใหญ่ Comparator- นี่คือคลาส "ตัวเปรียบเทียบ" ที่แยกจากกัน (การแปลค่อนข้างงุ่มง่าม แต่เข้าใจได้) หากเราจำเป็นต้องใช้การ เรียงลำดับที่เฉพาะเจาะจง เราไม่จำเป็นต้องเข้าไปในชั้นเรียนCarและเปลี่ยนตรรกะ compareTo()แต่เราสามารถสร้างคลาสตัวเปรียบเทียบแยกต่างหากในโปรแกรมของเราและสอนให้ทำการเรียงลำดับที่เราต้องการได้!
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()- นี่คือวิธีอินเทอร์เฟซComparatorซึ่งจะต้องนำไปใช้ ใช้วัตถุสองชิ้นเป็นอินพุตCarและเปรียบเทียบความเร็วสูงสุดในลักษณะปกติ (โดยการลบ) เช่นcompareTo()มันจะคืนค่าตัวเลข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()ใช้การเรียงลำดับตามธรรมชาติที่กำหนดไว้ใน เมธอด compareTo()คลาส Carแต่จะใช้อัลกอริธึมการเรียงลำดับจากตัวเปรียบเทียบที่ส่งผ่านไปแทน สิ่งนี้ให้ประโยชน์อะไรแก่เรา? ประการแรก ความเข้ากันได้กับโค้ดที่เขียน เราได้สร้างวิธีการจัดเรียงแบบใหม่เฉพาะเจาะจง โดยยังคงรักษาวิธีปัจจุบันไว้ ซึ่งจะใช้ในกรณีส่วนใหญ่ เราไม่ได้แตะชั้นเรียน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();
   }

   //...геттеры, сеттеры, toString()

}
ประการที่สองความยืดหยุ่น เราสามารถเพิ่มได้หลายประเภทตามที่เราต้องการ เช่น จัดเรียงรถตามสี ความเร็ว น้ำหนัก หรือจำนวนครั้งที่รถถูกใช้ในภาพยนตร์แบทแมน แค่สร้างเพิ่มอีกอันก็เพียงพอComparatorแล้ว นั่นคือทั้งหมด! วันนี้คุณได้เรียนรู้กลไกที่สำคัญมากสองประการที่คุณมักจะใช้ในโครงการจริงในที่ทำงาน แต่อย่างที่คุณทราบ ทฤษฎีที่ไม่มีการฝึกฝนนั้นไม่มีความหมายเลย ดังนั้นจึงถึงเวลาที่จะรวบรวมความรู้ของคุณและแก้ไขปัญหาต่าง ๆ ! :)
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION