Ghi đè phương thức (@Override)
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 22 trên 87.
Ghi đè phương thức (method overriding) cho phép lớp con tự triển khai một phương thức đã được định nghĩa trong lớp cha. Đây là cách các lớp con tùy chỉnh hành vi được kế thừa để phù hợp với nhu cầu cụ thể của mình.
Khi ghi đè một phương thức, phiên bản trong lớp con sẽ thay thế hoàn toàn phiên bản của lớp cha đối với các đối tượng thuộc lớp con đó. Phương thức phải có cùng tên và tham số với phương thức của lớp cha, đồng thời có kiểu trả về giống với kiểu của lớp cha hoặc là kiểu con của kiểu đó:
public class Animal {
public void makeSound() {
System.out.println("Some generic sound");
}
}
public class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Woof!");
}
}
public class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Meow!");
}
}Chú thích @Override cho trình biên dịch biết bạn định ghi đè một phương thức của lớp cha. Dù không bắt buộc, bạn vẫn nên dùng vì trình biên dịch sẽ phát hiện lỗi nếu bạn vô tình viết sai tên phương thức hoặc dùng sai tham số:
@Override
public void makeSound() { } // Chính xác, trình biên dịch kiểm tra điều này
public void makesound() { } // Lỗi gõ chữ! Tạo phương thức (method) mới thay vì ghi đè phương thức cũKhi bạn gọi một phương thức đã được ghi đè, Java sẽ chạy phiên bản thuộc về kiểu thực tế của đối tượng:
Dog dog = new Dog();
dog.makeSound(); // Đầu ra: Woof!
Cat cat = new Cat();
cat.makeSound(); // Đầu ra: Meow!Ở bài học trước, bạn đã biết có thể dùng super.methodName() bên trong một phương thức được ghi đè nếu bạn vẫn muốn giữ lại cách hoạt động của lớp cha cùng với đoạn code mới.
Thử thách
DễHãy xây dựng một hệ thống thông báo để tìm hiểu cách lớp con có thể ghi đè phương thức của lớp cha và cung cấp hành vi chuyên biệt riêng. Bạn sẽ thấy chú thích @Override giúp phát hiện lỗi như thế nào và cách mỗi lớp con tùy chỉnh các phương thức được kế thừa.
Bạn sẽ tạo ba tệp để sắp xếp code:
Notification.java: Tạo lớp cha đại diện cho một thông báo chung. Lớp này cần có:- Một trường private chứa
message(String) - Một hàm khởi tạo nhận message
- Một phương thức
getMessage()trả về message - Một phương thức
send()in ra:Sending notification: [message]
- Một trường private chứa
EmailNotification.java: Tạo một lớp con kế thừa từ Notification và tùy chỉnh cách gửi thông báo qua email:- Một trường private chứa địa chỉ email
recipient(String) - Một hàm khởi tạo nhận cả message và recipient, dùng
super(message)cho phần thuộc lớp cha - Ghi đè phương thức
send()bằng chú thích@Overrideđể in ra:Emailing [recipient]: [message]
- Một trường private chứa địa chỉ email
Main.java: Minh họa cách cùng một tên phương thức tạo ra hành vi khác nhau tùy vào kiểu đối tượng. Bạn sẽ nhận hai đầu vào: một message và một địa chỉ email. Tạo cả một Notification thông thường và một EmailNotification với cùng message, sau đó gọisend()trên từng đối tượng để xem đầu ra khác nhau.
Bạn sẽ nhận hai đầu vào: message (String) và địa chỉ email của recipient (String).
Đầu ra cần có hai dòng, dòng đầu tiên từ phương thức send() của lớp cha, sau đó là dòng từ phiên bản được ghi đè trong EmailNotification. Điều này minh họa cách ghi đè phương thức cho phép lớp con thay thế hành vi được kế thừa bằng cách triển khai riêng.
Tự làm thử
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Đọc dữ liệu đầu vào
String message = scanner.nextLine();
String recipient = scanner.nextLine();
// TODO: Tạo đối tượng Notification với message
// TODO: Tạo đối tượng EmailNotification với message và recipient
// TODO: Gọi send() trên đối tượng Notification
// TODO: Gọi send() trên đối tượng EmailNotification
}
}
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