Java - Ghi đè phương thức: Hướng dẫn Toàn diện Cho Người Mới Bắt Đầu

Chào bạn đến, những phù thủy Java tương lai! ? Hôm nay, chúng ta sẽ bắt đầu hành trình thú vị vào thế giới ghi đè phương thức trong Java. Đừng lo nếu bạn mới bắt đầu học lập trình; tôi sẽ là người hướng dẫn bạn thân thiện, giải thích mọi thứ từng bước. Vậy hãy lấy ly thức uống yêu thích của bạn, ngồi xuống và hãy bắt đầu!

Java - Overriding

Phương thức Ghi đè Là Gì?

Trước khi chúng ta đi sâu vào chi tiết, hãy bắt đầu với một so sánh đơn giản. Hãy tưởng tượng bạn có một công thức bánh quy sô-cô-la mà bạn kế thừa từ ông nội của mình. Đó là một công thức tuyệt vời, nhưng bạn quyết định thêm chút điều của riêng bạn bằng cách sử dụng sô-cô-la đen thay vì sô-cô-la sữa. Bạn không thay đổi toàn bộ công thức, chỉ thay đổi một phần của nó để phù hợp với khẩu vị của bạn. Đó chính là điều gì phương thức ghi đè là trong Java!

Trong lĩnh vực lập trình, phương thức ghi đè là tính năng cho phép lớp con cung cấp cách thực hiện cụ thể của một phương thức đã được định nghĩa trong lớp cha của nó. Đó như là nói, "Cảm ơn ông nội vì công thức, nhưng tôi sẽ thay đổi chút nào đó!"

Tại Sao Chúng Ta Cần Phương thức Ghi đè?

Phương thức ghi đè là một khái niệm cơ bản trong Lập trình Hướng Đối Tượng (OOP) và mang lại nhiều lợi ích:

  1. Nó cho phép bạn định nghĩa hành vi cụ thể cho lớp con.
  2. Nó hỗ trợ khái niệm đa hình, mà chúng ta sẽ thảo luận sau.
  3. Nó cải thiện khả năng tái sử dụng và linh hoạt của mã.

Cách Phương thức Ghi đè Hoạt Động

Hãy xem một ví dụ đơn giản để hiểu cách phương thức ghi đè hoạt động:

class Animal {
public void makeSound() {
System.out.println("Con vật này làm tiếng");
}
}

class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Con chó gâu gâu: Woof! Woof!");
}
}

public class Main {
public static void main(String[] args) {
Animal myAnimal = new Animal();
Animal myDog = new Dog();

myAnimal.makeSound();  // Output: Con vật này làm tiếng
myDog.makeSound();     // Output: Con chó gâu gâu: Woof! Woof!
}
}

Trong ví dụ này, chúng ta có một lớp cha Animal với phương thức makeSound(). Lớp Dog mở rộng Animal và ghi đè phương thức makeSound() để cung cấp cách thực hiện cụ thể cho chó.

Khi chúng ta tạo một thể hiện của Animal và gọi makeSound(), nó sử dụng phương thức từ lớp Animal. Tuy nhiên, khi chúng ta tạo một thể hiện của Dog và gọi makeSound(), nó sử dụng phương thức đã ghi đè từ lớp Dog.

Phần Annotation @Override

Bạn có thể nhận ra phần annotation @Override trong ví dụ của chúng ta. Đó là một thực hành tốt trong Java. Nó cho phép trình biên dịch biết rằng chúng ta định ghi đè một phương thức từ lớp cha. Nếu chúng ta nhầm lẫn tên phương thức hoặc sử dụng các tham số sai, trình biên dịch sẽ bắt lỗi cho chúng ta. Đó như có một người giúp đỡ thân thiện đứng sau vai bạn!

Quy Tắc cho Phương thức Ghi đè

Bây giờ, hãy nói về một số quy tắc quan trọng cần nhớ khi ghi đè phương thức:

  1. Phương thức trong lớp con phải có cùng tên với phương thức trong lớp cha.
  2. Phương thức trong lớp con phải có cùng danh sách tham số với phương thức trong lớp cha.
  3. Loại trả về phải trùng khớp hoặc là kiểu con của loại trả về được khai báo trong phương thức lớp cha.
  4. Mức độ truy cập không thể hạn chế hơn mức độ truy cập của phương thức bị ghi đè.
  5. Phương thức thể hiện chỉ có thể được ghi đè nếu chúng được kế thừa bởi lớp con.
  6. Phương thức được khai báo là final không thể được ghi đè.
  7. Phương thức được khai báo là static không thể được ghi đè nhưng có thể được khai báo lại.
  8. Nếu một phương thức không thể được kế thừa, nó không thể được ghi đè.
  9. Các phương thức khởi tạo không thể được ghi đè.

Hãy đặt các quy tắc này vào một bảng tiện lợi:

Quy tắc Mô tả
Tên Phương thức Phải trùng với phương thức trong lớp cha
Tham số Phải khớp với phương thức trong lớp cha
Loại trả về Trùng hoặc kiểu con của phương thức lớp cha
Mức độ truy cập Không thể hạn chế hơn
Phương thức thể hiện Có thể ghi đè nếu được kế thừa
Phương thức final Không thể ghi đè
Phương thức static Không thể ghi đè (có thể khai báo lại)
Kế thừa Phương thức phải có thể kế thừa để ghi đè
Phương thức khởi tạo Không thể ghi đè

Sử Dụng Từ Khóa super

Đôi khi, bạn có thể muốn gọi phương thức bị ghi đè từ lớp cha trong lớp con của bạn. Đó là nơi từ khóa super trở nên hữu ích. Hãy sửa đổi ví dụ trước đó của chúng ta:

class Animal {
public void makeSound() {
System.out.println("Con vật này làm tiếng");
}
}

class Dog extends Animal {
@Override
public void makeSound() {
super.makeSound();  // Gọi phương thức của lớp cha
System.out.println("Con chó gâu gâu: Woof! Woof!");
}
}

public class Main {
public static void main(String[] args) {
Dog myDog = new Dog();
myDog.makeSound();
}
}

Output:

Con vật này làm tiếng
Con chó gâu gâu: Woof! Woof!

Trong ví dụ này, chúng ta sử dụng super.makeSound() để gọi phương thức makeSound() từ lớp Animal trước khi thêm hành vi cụ thể của chó. Đó như nói, "Trước hết làm theo những gì con vật thường làm, sau đó làm theo những gì con chó cụ thể làm."

Sức Mạnh của Đa Hình

Phương thức ghi đè liên quan gần với khái niệm mạnh mẽ của OOP có tên là đa hình. Đa hình cho phép chúng ta sử dụng tham chiếu lớp cha để chỉ đến thể hiện của lớp con. Hãy xem một ví dụ:

class Shape {
public void draw() {
System.out.println("Vẽ một hình");
}
}

class Circle extends Shape {
@Override
public void draw() {
System.out.println("Vẽ một hình tròn");
}
}

class Square extends Shape {
@Override
public void draw() {
System.out.println("Vẽ một hình vuông");
}
}

public class Main {
public static void main(String[] args) {
Shape shape1 = new Circle();
Shape shape2 = new Square();

shape1.draw();  // Output: Vẽ một hình tròn
shape2.draw();  // Output: Vẽ một hình vuông
}
}

Trong ví dụ này, chúng ta sử dụng tham chiếu Shape để giữ thể hiện của CircleSquare. Khi chúng ta gọi phương thức draw(), Java biết sử dụng phương thức đã ghi đè trong lớp con tương ứng. Đó là ma thuật của đa hình!

Kết Luận

Và thế là, các bạn đã vượt qua các khái niệm cơ bản về phương thức ghi đè trong Java, từ định nghĩa đến quy tắc và ứng dụng thực tế. Hãy nhớ, phương thức ghi đè như thêm chút điều của riêng bạn vào công thức gia đình – nó cho phép bạn tùy chỉnh hành vi kế thừa trong khi duy trì cấu trúc tổng thể.

Khi tiếp tục hành trình với Java, bạn sẽ tìm thấy phương thức ghi đè là một công cụ không thể thiếu trong túi kiến thức lập trình của bạn. Nó là một khái niệm quan trọng giúp mã của bạn trở nên linh hoạt hơn, tái sử dụng hơn và gần gũi hơn với lập trình hướng đối tượng.

Hãy tiếp tục luyện tập, giữ được sự tò mò và hạnh phúc lập trình! ??‍??‍?

Credits: Image by storyset