compareTo() và Comparable
Thuộc phần Lập trình hướng đối tượng trong hành trình Java của Coddy. Bài học 44 trên 87.
Giao diện Comparable cho phép các đối tượng xác định thứ tự tự nhiên. Khi triển khai giao diện này, lớp có thể tự động được sắp xếp bằng các phương thức như Collections.sort() hoặc được lưu trong các bộ sưu tập đã sắp xếp như TreeSet.
Giao diện yêu cầu bạn triển khai một phương thức duy nhất: compareTo(). Phương thức này so sánh đối tượng hiện tại với một đối tượng khác và trả về một số nguyên cho biết thứ tự tương đối của chúng:
- Giá trị âm: đối tượng này đứng trước đối tượng kia
- Số không: hai đối tượng bằng nhau
- Giá trị dương: đối tượng này đứng sau đối tượng kia
public class Person implements Comparable<Person> {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int compareTo(Person other) {
return Integer.compare(this.age, other.age); // Sắp xếp theo tuổi tăng dần
}
}Sau khi triển khai, việc sắp xếp trở nên đơn giản:
List<Person> people = new ArrayList<>();
people.add(new Person("Alice", 30));
people.add(new Person("Bob", 25));
Collections.sort(people); // Giờ danh sách đã sắp xếp theo tuổi: Bob, AliceĐể so sánh chuỗi hoặc các trường Comparable khác, bạn có thể dùng phương thức compareTo() của chúng thay vì phép trừ: return this.name.compareTo(other.name);. Cách này an toàn hơn và xử lý đúng các trường hợp đặc biệt. Với trường int, hãy ưu tiên Integer.compare(a, b) thay cho a - b, vì phép trừ có thể gây tràn số với các giá trị cực lớn.
Thử thách
DễHãy xây dựng một hệ thống xếp hạng phim sử dụng giao diện Comparable để sắp xếp phim theo điểm đánh giá. Bạn sẽ tạo lớp Movie có thể so sánh với các phim khác, nhờ đó phim tự động được sắp xếp từ điểm cao nhất đến thấp nhất.
Bạn sẽ tổ chức code trong hai tệp:
Movie.java: Tạo một lớp đại diện cho phim có thể so sánh với các phim khác. Một Movie có ba thuộc tính riêng tư:title(String),director(String) vàrating(double, từ 0.0 đến 10.0). Thêm hàm khởi tạo để khởi tạo tất cả thuộc tính và các phương thức getter cho từng thuộc tính.Cho lớp Movie triển khai
Comparable<Movie>và ghi đè phương thứccompareTo(). Phim cần được sắp xếp theo điểm đánh giá theo thứ tự giảm dần (điểm cao nhất đứng đầu). Khi so sánh các số thực double, hãy dùngDouble.compare()để so sánh an toàn: nhớ đảo thứ tự khi sắp xếp giảm dần!Ghi đè
toString()để trả về:[title] by [director] - Rating: [rating]Main.java: Tạo danh sách phim và sắp xếp chúng để sử dụng lớp Movie. Bạn sẽ nhận đầu vào gồm ba phim, mỗi phim trên một dòng riêng theo định dạng:title,director,ratingPhân tích từng dòng để tạo các đối tượng Movie, thêm chúng vào một
ArrayList, sau đó dùngCollections.sort()để sắp xếp danh sách. Nhờ phần triển khaiComparable, các phim sẽ tự động được sắp xếp theo điểm đánh giá!Sau khi sắp xếp, in từng phim trên một dòng riêng theo định dạng
toString(). Phim có điểm cao nhất sẽ xuất hiện đầu tiên.
Bạn sẽ nhận đầu vào gồm ba dòng, mỗi dòng chứa dữ liệu phim theo định dạng: title,director,rating
Ví dụ, một dòng đầu vào có thể như sau: Inception,Christopher Nolan,8.8
Nhớ nhập java.util.ArrayList, java.util.Collections và java.util.Scanner vào tệp Main. Hãy chú ý cách triển khai Comparable cho phép bạn sắp xếp các đối tượng tùy chỉnh chỉ bằng một lần gọi phương thức, không cần bộ so sánh bổ sung!
Tự làm thử
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Đọc ba dòng dữ liệu phim
String line1 = scanner.nextLine();
String line2 = scanner.nextLine();
String line3 = scanner.nextLine();
// TODO: Tạo một ArrayList để lưu các đối tượng Movie
// TODO: Phân tích từng dòng (định dạng: title,director,rating)
// Gợi ý: Dùng split(",") để tách các phần
// Gợi ý: Dùng Double.parseDouble() cho rating
// TODO: Tạo các đối tượng Movie và thêm vào danh sách
// TODO: Sắp xếp danh sách bằng Collections.sort()
// TODO: In ra từng phim (mỗi dòng một phim)
}
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Kiến thức cơ bản về lập trình hướng đối tượng
Tệp bên ngoàiGiới thiệu về lập trình hướng đối tượngLớp và đối tượngTừ khóa thisPhương thứcTrường (thuộc tính)Phương thức khởi tạoNạp chồng phương thức khởi tạoÔn tập: Máy tính đơn giản4Kế thừa
Kế thừa cơ bản (extends)Từ khóa superGhi đè phương thức (@Override)Chuỗi gọi hàm khởi tạoLớp ObjectKế thừa đơn và đa cấpVì sao không hỗ trợ kế thừa nhiều lớpÔn tập: Phân cấp lớp Employee7Phương thức đặc biệt và lớp Object
Phương thức toString()equals() và hashCode()Phương thức clone()compareTo() và ComparableGiao diện ComparatorÔn tập: sắp xếp tùy chỉnh2Bộ điều chỉnh quyền truy cập và đóng gói
Tổng quan về các mức truy cậpPhương thức getter và setterẨn thông tinTừ khóa finalÔn tập: Trình quản lý tài khoản ngân hàng5Tính đa hình
Kiến thức cơ bản về nạp chồng phương thứcGhi đè phương thức (thời gian chạy)Chuyển kiểu lên và chuyển kiểu xuốngToán tử instanceofLớp và phương thức trừu tượngÔn tập: máy tính hình học8Khái niệm OOP nâng cao
Kết hợp và kế thừaKết tập và hợp thànhLớp bên trong, lớp lồng nhau và lớp ẩn danhKiểu enum và phương thức enumBản ghi (Java 16+)Lớp sealed (Java 17+)3Thuộc tính lớp và thành viên tĩnh
Biến của instance và biến tĩnhPhương thức tĩnhKhối tĩnhHằng số (static final)Ôn tập: bộ đếm và tiện ích6Giao diện và lớp trừu tượng
Giới thiệu về giao diệnTriển khai giao diệnTriển khai nhiều giao diệnPhương thức mặc định và tĩnh trong giao diệnLớp trừu tượng và giao diệnGiao diện hàmÔn tập: hệ thống thanh toán9Kiểu tổng quát
Giới thiệu về kiểu tổng quátLớp tổng quátPhương thức tổng quátTham số kiểu có giới hạnKý tự đại diện (?, extends, super)Ôn tập: vùng chứa tổng quát12Mẫu thiết kế, phần 2
Mẫu CommandMẫu AdapterMẫu DecoratorMẫu Template MethodMẫu StateMẫu CompositeMẫu IteratorTự luyện tập: Trình biên dịch Java online