Trong bài hướng dẫn trước, chúng ta đã tìm hiểu về khái niệm kế thừa. Kế thừa là một thuộc tính trong lập trình hướng đối tượng (OOP) cho phép chúng ta tạo ra một lớp con mới (lớp con) từ một lớp hiện có (lớp cha). Lớp con kế thừa các thuộc tính và phương thức từ lớp cha.
Bây giờ, nếu cùng một phương thức được định nghĩa cả trong lớp cha và lớp con, thì phương thức của lớp con sẽ ghi đè phương thức của lớp cha. Điều này được gọi là phương thức ghi đè.
Ví dụ 1: Phương thức Ghi đè
class Animal { public void displayInfo() { System.out.println("Tôi là một động vật."); } } class Dog extends Animal { @Override public void displayInfo() { System.out.println("Tôi là một con chó."); } } class Main { public static void main(String[] args) { Dog d1 = new Dog(); d1.displayInfo(); } }
Kết quả:
Tôi là một con chó.
Trong chương trình trên, phương thức displayInfo() được định nghĩa cả trong lớp cha Animal và lớp con Dog.
Khi chúng ta gọi displayInfo() bằng đối tượng d1
(đối tượng của lớp con), phương thức trong lớp con Dog được gọi. Phương thức displayInfo() của lớp con ghi đè lên phương thức cùng tên của lớp cha.
Lưu ý việc sử dụng chú thích @Override
trong ví dụ của chúng ta. Trong ngôn ngữ Java, chú thích là thông tin về dữ liệu mà chúng ta sử dụng để cung cấp thông tin cho trình biên dịch. Ở đây, chú thích @Override
cho biết trình biên dịch rằng phương thức sau chú thích này ghi đè phương thức của lớp cha.
Việc sử dụng @Override
không bắt buộc. Tuy nhiên, khi chúng ta sử dụng nó, phương thức phải tuân thủ tất cả các quy tắc về ghi đè. Nếu không, trình biên dịch sẽ tạo ra lỗi.
Quy tắc Ghi đè trong Java
- Cả lớp cha và lớp con phải có cùng tên phương thức, cùng kiểu trả về và cùng danh sách tham số.
- Chúng ta không thể ghi đè phương thức được khai báo là final và static.
- Chúng ta luôn luôn nên ghi đè các phương thức trừu tượng của lớp cha (sẽ được thảo luận trong các bài hướng dẫn sau).
Từ khoá super trong Ghi đè Java
Một câu hỏi phổ biến đặt ra khi thực hiện ghi đè trong Java là:
Chúng ta có thể truy cập phương thức của lớp cha sau khi đã ghi đè không?
Đáp án là Có. Để truy cập phương thức của lớp cha từ lớp con, chúng ta sử dụng từ khoá super
.
Ví dụ 2: Sử dụng từ khoá super
class Animal { public void displayInfo() { System.out.println("Tôi là một động vật."); } } class Dog extends Animal { public void displayInfo() { super.displayInfo(); System.out.println("Tôi là một con chó."); } } class Main { public static void main(String[] args) { Dog d1 = new Dog(); d1.displayInfo(); } }
Kết quả:
Tôi là một động vật. Tôi là một con chó.
Trong ví dụ trên, lớp con Dog ghi đè phương thức displayInfo() của lớp cha Animal.
Khi chúng ta gọi phương thức displayInfo() bằng đối tượng d1
của lớp con Dog, phương thức trong lớp con Dog được gọi; phương thức trong lớp cha không được gọi.
Bên trong displayInfo() của lớp con Dog, chúng ta đã sử dụng super.displayInfo()
để gọi phương thức displayInfo() của lớp cha.
Chú ý rằng, constructor (hàm tạo) trong Java không được kế thừa. Do đó, không tồn tại khái niệm ghi đè constructor trong Java.
Tuy nhiên, chúng ta có thể gọi constructor của lớp cha từ các lớp con của nó. Để làm điều này, chúng ta sử dụng super()
. Để biết thêm thông tin, hãy truy cập Java super keyword.
Các từ khoá truy cập trong Ghi đè Phương thức
Cùng một phương thức được khai báo trong lớp cha và các lớp con có thể có các từ khoá truy cập khác nhau. Tuy nhiên, có một hạn chế.
Chúng ta chỉ có thể sử dụng các từ khoá truy cập trong các lớp con mà cung cấp quyền truy cập lớn hơn so với từ khoá truy cập của lớp cha. Ví dụ,
Giả sử, một phương thức myClass()
trong lớp cha được khai báo là protected
. Khi đó, phương thức myClass()
trong lớp con có thể là public
hoặc protected
, nhưng không thể là private
.
Ví dụ 3: Từ khoá truy cập trong Ghi đè
class Animal { protected void displayInfo() { System.out.println("Tôi là một động vật."); } } class Dog extends Animal { public void displayInfo() { System.out.println("Tôi là một con chó."); } } class Main { public static void main(String[] args) { Dog d1 = new Dog(); d1.displayInfo(); } }
Kết quả:
Tôi là một con chó.
Trong ví dụ trên, lớp con Dog ghi đè phương thức displayInfo() của lớp cha Animal.
Khi chúng ta gọi phương thức displayInfo() bằng đối tượng d1
của lớp con Dog, phương thức trong lớp con được gọi.
Chú ý rằng, phương thức displayInfo() được khai báo với từ khoá protected
trong lớp cha Animal. Trong lớp con Dog, phương thức cùng tên này có từ khoá public
. Điều này là có thể bởi vì public
cung cấp quyền truy cập lớn hơn protected
.
Ghi đè Phương thức Trừu tượng
Trong Java, lớp trừu tượng được tạo ra để là lớp cha của các lớp khác. Và, nếu một lớp chứa một phương thức trừu tượng, thì buộc phải ghi đè nó.
Chúng ta sẽ tìm hiểu thêm về các lớp trừu tượng và việc ghi đè phương thức trừu tượng trong các bài hướng dẫn tiếp theo.