CHÀO! Bạn đã sử dụng các phương thức Java và biết nhiều về chúng. Cách ghi đè phương thức hoạt động - 1Chắc chắn bạn đã bắt gặp một lớp có nhiều phương thức có tên giống nhau nhưng danh sách đối số khác nhau. Bạn sẽ nhớ lại rằng trong những trường hợp đó, chúng tôi đã sử dụng nạp chồng phương thức. Hôm nay chúng ta sẽ xem xét một tình huống khác. Hãy tưởng tượng rằng chúng ta có một phương thức chung, nhưng nó sẽ làm những việc khác nhau tùy thuộc vào lớp mà nó được gọi. Làm thế nào để chúng ta thực hiện hành vi này? Để hiểu điều này, hãy lấy Animallớp cha, đại diện cho động vật và tạo một speakphương thức trong đó:
public class Animal {

   public void speak() {

       System.out.println("Hello!");
   }
}
Mặc dù chúng tôi chỉ mới bắt đầu viết chương trình của mình, nhưng bạn có thể thấy một vấn đề tiềm ẩn: thế giới có rất nhiều loài động vật và tất cả chúng đều "nói" khác nhau: mèo kêu, vịt kêu, rắn rít, v.v. Mục tiêu của chúng tôi rất đơn giản: chúng Cách ghi đè phương thức hoạt động - 2tôi muốn tránh tạo ra một loạt các phương pháp để nói. Thay vì tạo một meow()phương thức để kêu meo meo, hiss()rít lên, v.v., chúng ta muốn con rắn rít lên, con mèo kêu meo meo và con chó sủa khi phương speak()thức được gọi. Chúng ta có thể dễ dàng đạt được điều này bằng cách ghi đè phương thức . Wikipedia giải thích thuật ngữ này như sau: Method overriding, trong lập trình hướng đối tượng, là một tính năng ngôn ngữ cho phép một lớp con hoặc lớp con cung cấp một triển khai cụ thể của một phương thức đã được cung cấp bởi một trong các lớp cha hoặc lớp cha của nó. Điều đó về cơ bản là chính xác. Việc ghi đè cho phép bạn sử dụng một số phương thức của lớp cha và viết cách triển khai của riêng bạn trong mỗi lớp dẫn xuất. Việc thực hiện mới trong lớp con "thay thế" một trong cha mẹ. Hãy xem điều này trông như thế nào với một ví dụ. Hãy tạo 4 hậu duệ của Animallớp chúng ta:
public class Bear extends Animal {
   @Override
   public void speak() {
       System.out.println("Growl!");
   }
}
public class Cat extends Animal {

   @Override
   public void speak() {
       System.out.println("Meow!");
   }
}

public class Dog extends Animal {

   @Override
   public void speak() {
       System.out.println("Woof!");
   }
}


public class Snake extends Animal {

   @Override
   public void speak() {
       System.out.println("Hiss!");
   }
}
Đây là một mẹo nhỏ cho tương lai: để ghi đè các phương thức của lớp cha, hãy truy cập vào mã của lớp dẫn xuất trong IntelliJ IDE , nhấn Ctrl+O và chọn Ghi đè các phương thức... từ menu. Làm quen với việc sử dụng các phím nóng ngay từ đầu. Họ sẽ tăng tốc độ mã hóa! Để có được hành vi mong muốn, chúng tôi đã thực hiện một số điều sau:
  1. Trong mỗi lớp con, chúng tôi đã tạo một phương thức có cùng tên với phương thức trong lớp cha.
  2. Chúng tôi đã nói với trình biên dịch rằng chúng tôi không chỉ đặt tên cho phương thức giống như trong lớp cha mà chúng tôi muốn ghi đè lên hành vi của nó. "Thông báo" này tới trình biên dịch được chuyển tải qua chú thích @Override .
    Chú thích @Override bên trên một phương thức cho trình biên dịch biết (cũng như các lập trình viên khác đang đọc mã của bạn), "Đừng lo. Đây không phải là nhầm lẫn hay giám sát. Tôi biết rằng phương thức này đã tồn tại và tôi muốn ghi đè lên nó .

  3. Chúng tôi đã viết phần triển khai mà chúng tôi cần cho mỗi lớp con cháu. Khi speak()phương thức được gọi, một con rắn sẽ rít lên, một con gấu sẽ gầm gừ, v.v.
Hãy xem cách nó hoạt động trong một chương trình:
public class Main {

   public static void main(String[] args) {

       Animal animal1 = new Dog();
       Animal animal2 = new Cat();
       Animal animal3 = new Bear();
       Animal animal4 = new Snake();

       animal1.speak();
       animal2.speak();
       animal3.speak();
       animal4.speak();
   }
}
Đầu ra bảng điều khiển:

Woof! 
Meow! 
Growl! 
Hiss!
Tuyệt vời, mọi thứ hoạt động như bình thường! Chúng ta đã tạo 4 biến tham chiếu có kiểu là Animallớp cha và gán cho chúng 4 đối tượng khác nhau của các lớp con. Kết quả là, mỗi đối tượng hành xử khác nhau. Đối với mỗi lớp dẫn xuất, speak()phương thức được ghi đè sẽ thay thế phương thức hiện có speak()của Animallớp (chỉ hiển thị "Nói: " trên bảng điều khiển). Cách ghi đè phương thức hoạt động - 3Ghi đè phương thức có một số hạn chế:
  1. Một phương thức được ghi đè phải có cùng các đối số như phương thức trong lớp cha.

    Nếu speakphương thức của lớp cha lấy a Stringlàm đầu vào, thì phương thức bị ghi đè trong lớp con cũng phải lấy a Stringlàm đầu vào. Nếu không, trình biên dịch sẽ báo lỗi:

    public class Animal {
    
       public void speak(String s) {
    
           System.out.println("Speaking: " + s);
       }
    }
    
    public class Cat extends Animal {
    
       @Override // Error!
       public void speak() {
           System.out.println("Meow!");
       }
    }

  2. Phương thức được ghi đè phải có cùng kiểu trả về với phương thức trong lớp cha.

    Nếu không, chúng ta sẽ gặp lỗi biên dịch:

    public class Animal {
    
       public void speak() {
    
           System.out.println("Hello!");
       }
    }
    
    
    public class Cat extends Animal {
    
       @Override
       public String speak() {         // Error!
           System.out.println("Meow!");
           return "Meow!";
       }
    }

  3. Công cụ sửa đổi truy cập của phương thức bị ghi đè cũng không thể khác với công cụ sửa đổi truy cập ban đầu:

    public class Animal {
    
       public void speak() {
    
           System.out.println("Hello!");
       }
    }
    
    public class Cat extends Animal {
    
       @Override
       private void speak() {      // Error!
           System.out.println("Meow!");
       }
    }
Trong Java, ghi đè phương thức là một cách để thực hiện tính đa hình. Điều đó có nghĩa là ưu điểm chính của nó là tính linh hoạt mà chúng ta đã nói trước đó. Chúng ta có thể xây dựng một hệ thống phân cấp đơn giản và hợp lý của các lớp, mỗi lớp có hành vi cụ thể (chó sủa, mèo kêu) nhưng có một giao diện duy nhất — một speak()phương thức duy nhất cho mọi người thay vì một loạt các phương thức khác nhau, ví dụ bark(): meow(), v.v.