CodeGym/Blog Java/Ngẫu nhiên/Lớp so sánh của Java

Lớp so sánh của Java

Xuất bản trong nhóm
CHÀO! Hôm nay chúng ta sẽ nói về việc so sánh các đối tượng. Lớp so sánh của Java - 1 Hmm... Nhưng không phải chúng ta đã nói về chủ đề này hơn một lần rồi sao? :/ Chúng ta biết cách thức ==hoạt động của toán tử, cũng như các phương thức equals()hashCode(). So sánh có chút khác biệt. Trước đây, chúng tôi rất có thể có nghĩa là "kiểm tra các đối tượng cho bình đẳng". Nhưng lý do để so sánh các đối tượng với nhau có thể hoàn toàn khác nhau! Rõ ràng nhất trong số này là phân loại. Tôi nghĩ nếu bạn được yêu cầu sắp xếp một ArrayList<>số hoặc chuỗi, bạn sẽ có thể xử lý việc này mà không gặp vấn đề gì:
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);
   }
}
Đầu ra bảng điều khiển:
[Dasha, Masha, Sasha]
Nếu bạn nhớ Collectionslớp và sort()phương thức của nó, thì tốt lắm! Tôi nghĩ bạn cũng sẽ không gặp rắc rối với những con số. Đây là một nhiệm vụ khó khăn hơn cho bạn:
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);
   }
}
Nhiệm vụ thực sự đơn giản. Chúng ta có một Carlớp và 3 đối tượng Car. Bạn vui lòng sắp xếp những chiếc xe trong danh sách? Bạn có thể sẽ hỏi, "Làm thế nào chúng nên được sắp xếp?" Bằng tên? Theo năm sản xuất? Bằng tốc độ tối đa? Câu hỏi tuyệt vời. Hiện tại, chúng tôi không biết cách sắp xếp các Carđối tượng. Và, một cách hoàn toàn tự nhiên, Java cũng không biết điều đó! Khi chúng tôi cố gắng chuyển một danh sách Carcác đối tượng cho Collections.sort()phương thức, chúng tôi gặp lỗi:
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);
   }
}
Và thực sự, làm thế nào để ngôn ngữ biết cách sắp xếp các đối tượng của các lớp mà bạn đã viết? Điều này phụ thuộc vào những gì chương trình của bạn cần làm. Bằng cách nào đó, chúng ta phải dạy Java so sánh các đối tượng này. Và để so sánh chúng theo cách chúng ta muốn. Java có một cơ chế đặc biệt cho việc này: Comparablegiao diện. Để bằng cách nào đó so sánh và sắp xếp Carcác đối tượng của chúng ta, lớp phải triển khai giao diện này, bao gồm một phương thức duy nhất: 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()

}
Xin lưu ýmà chúng tôi đã chỉ định Comparable<Car>giao diện, không chỉ Comparable. Đây là một giao diện được tham số hóa, tức là chúng ta phải chỉ định lớp liên quan cụ thể. Về nguyên tắc, bạn có thể xóa <Car>khỏi giao diện, nhưng khi đó việc so sánh sẽ Objectmặc định dựa trên các đối tượng. Thay vì compareTo(Car o)phương thức, lớp của chúng ta sẽ có:
@Override
   public int compareTo(Object o) {
       return 0;
   }
Tất nhiên, chúng tôi làm việc với Car. Bên trong compareTo()phương thức, chúng tôi triển khai logic của mình để so sánh ô tô. Giả sử chúng ta cần sắp xếp chúng theo năm sản xuất. Bạn có thể nhận thấy rằng compareTo()phương thức này trả về một int, không phải một boolean. Đừng để điều này làm bạn ngạc nhiên. Khi chúng ta so sánh hai đối tượng, có 3 khả năng xảy ra:
  • а < b
  • a > b
  • a == b.
booleanchỉ có 2 giá trị: đúng và sai, không hoạt động tốt để so sánh các đối tượng. Với int, mọi thứ đơn giản hơn nhiều. Nếu giá trị trả về là > 0, thì a > b. Nếu kết quả của compareTo< 0, thì a < b. Và, nếu kết quả là == 0, thì hai đối tượng bằng nhau: a == b. Dạy lớp chúng ta phân loại ô tô theo năm sản xuất thật dễ dàng:
@Override
public int compareTo(Car o) {
   return this.getManufactureYear() - o.getManufactureYear();
}
Nhưng những gì đang xảy ra ở đây? Chúng tôi lấy một đối tượng Ô tô ( this), lấy năm sản xuất của ô tô này và trừ đi năm sản xuất của một ô tô khác (chiếc mà đối tượng đang được so sánh với nó). Nếu năm sản xuất của chiếc ô tô đầu tiên lớn hơn, phương thức sẽ trả về một int > 0. Điều này có nghĩa là chiếc this car >xe o. Ngược lại, nếu năm sản xuất của chiếc ô tô thứ hai ( о) lớn hơn thì phương thức sẽ trả về một số âm, nghĩa là o > this. Cuối cùng, nếu chúng bằng nhau thì phương thức sẽ trả về 0. Cơ chế đơn giản này đã đủ để chúng ta sắp xếp các bộ sưu tập Carđối tượng! Bạn không phải làm bất cứ điều gì khác. Kiểm tra nó ra:
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);
   }
}
Đầu ra bảng điều khiển:
[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}]
Những chiếc xe được sắp xếp như chúng ta muốn! :) Lớp so sánh của Java - 2Khi nào tôi nên sử dụng Comparable? Phương pháp so sánh được thực hiện trong Comparableđược gọi là thứ tự tự nhiên. Điều này là do trong compareTo()phương thức bạn định nghĩa cách phổ biến nhất hoặc tự nhiên nhất để so sánh các đối tượng của lớp này. Java đã có thứ tự tự nhiên. Ví dụ, Java biết rằng các chuỗi thường được sắp xếp theo thứ tự bảng chữ cái và các số theo giá trị số tăng dần. Do đó, nếu bạn gọi sort()phương thức trên danh sách các số hoặc chuỗi, chúng sẽ được sắp xếp. Nếu chương trình của chúng ta thường so sánh và sắp xếp ô tô theo năm sản xuất, thì chúng ta nên xác định cách sắp xếp tự nhiên cho Ô tô bằng cách sử dụng giao Comparable<Car>diện vàcompareTo()phương pháp. Nhưng nếu điều này là không đủ cho chúng ta thì sao? Hãy tưởng tượng rằng chương trình của chúng ta không đơn giản như vậy. Trong hầu hết các trường hợp, việc phân loại ô tô tự nhiên (mà chúng tôi đã thiết lập để thực hiện theo năm sản xuất) phù hợp với chúng tôi. Nhưng đôi khi khách hàng của chúng tôi là những người đam mê lái xe nhanh. Nếu chúng ta đang chuẩn bị một danh mục ô tô để họ nghiên cứu, thì ô tô nên được sắp xếp theo tốc độ tối đa. Lớp so sánh của Java - 3Ví dụ: giả sử chúng ta cần sắp xếp như thế này 15% thời gian. Điều này rõ ràng là không đủ để chúng tôi thiết lập Carphân loại tự nhiên của lớp theo tốc độ thay vì theo năm sản xuất. Nhưng chúng tôi không thể bỏ qua 15% khách hàng của mình. Vậy ta phải làm sao? Một giao diện khác hỗ trợ chúng tôi tại đây: Comparator. Giống như Comparable, nó là một giao diện được tham số hóa. Có gì khác biệt? Comparablelàm cho các đối tượng của chúng ta "có thể so sánh được" và xác định thứ tự sắp xếp tự nhiên nhất của chúng, tức là thứ tự sắp xếp sẽ được sử dụng trong hầu hết các trường hợp. Comparatorlà một giao diện "so sánh" riêng biệt. Nếu chúng ta cần thực hiện một số loại thứ tự sắp xếp đặc biệt, chúng ta không cần phải vào lớp Carvà thay đổi logic của compareTo(). Thay vào đó, chúng ta có thể tạo một lớp riêng thực hiện Bộ so sánh và dạy nó cách thực hiện sắp xếp mà chúng ta cần!
import java.util.Comparator;

public class MaxSpeedCarComparator implements Comparator<Car> {

   @Override
   public int compare(Car o1, Car o2) {
       return o1.getMaxSpeed() - o2.getMaxSpeed();
   }
}
Như bạn có thể thấy, của chúng tôi Comparatorlà khá đơn giản. Chúng ta chỉ cần triển khai một phương thức giao diện: compare(). Nó lấy hai Carđối tượng làm đầu vào và so sánh tốc độ tối đa của chúng theo cách thông thường (bằng phép trừ). Like compareTo(), nó trả về an intvà nguyên tắc so sánh là giống nhau. Làm thế nào để chúng tôi sử dụng này? Tất cả đều đơn giản:
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);
   }
}
Đầu ra bảng điều khiển:
[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}]
Chúng ta chỉ cần tạo một đối tượng so sánh và truyền nó cho Collections.sort()phương thức cùng với danh sách cần sắp xếp. Khi sort()phương thức nhận được một bộ so sánh, nó không sử dụng cách sắp xếp tự nhiên được định nghĩa trong phương thức Carcủa lớp compareTo(). Thay vào đó, nó áp dụng thuật toán sắp xếp được xác định bởi bộ so sánh được truyền cho nó. những lợi thế của việc này là gì? Đầu tiên, khả năng tương thích với mã hiện có. Chúng tôi đã tạo một phương pháp sắp xếp mới, đặc biệt, trong khi vẫn giữ nguyên phương pháp hiện tại sẽ được sử dụng thường xuyên. Chúng tôi đã không chạm vào Carlớp học cả. Đó là một Comparable, và vì vậy nó vẫn là:
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()

}
Thứ hai, tính linh hoạt. Chúng ta có thể thêm bao nhiêu thuật toán sắp xếp tùy thích. Ví dụ: chúng ta có thể sắp xếp ô tô theo màu sắc, tốc độ, trọng lượng hoặc theo số lần ô tô đã được sử dụng trong phim Batman. Tất cả những gì chúng ta cần làm là tạo một tệp Comparator. Đó là nó! Hôm nay bạn đã nghiên cứu hai cơ chế rất quan trọng mà bạn sẽ thường sử dụng trong các dự án thực tế tại nơi làm việc. Nhưng, như bạn đã biết, lý thuyết mà không có thực hành là không có gì. Bây giờ là lúc để củng cố kiến ​​​​thức của bạn và hoàn thành một số nhiệm vụ!
Bình luận
  • Phổ biến
  • Mới
Bạn phải đăng nhập để đăng nhận xet
Trang này chưa có bất kỳ bình luận nào