Java - Ghi đè

Trong chương trước, chúng ta đã nói về lớp cha và lớp con. Nếu một lớp kế thừa một phương thức từ lớp cha của nó, thì sẽ có cơ hội ghi đè phương thức với điều kiện là nó không được đánh dấu là cuối cùng.

Lợi ích của việc ghi đè là: khả năng xác định một hành vi cụ thể cho kiểu lớp con, có nghĩa là một lớp con có thể triển khai một phương thức của lớp cha dựa trên yêu cầu của nó.

Theo thuật ngữ hướng đối tượng, ghi đè có nghĩa là ghi đè chức năng của một phương thức hiện có.

Thí dụ

Chúng ta hãy xem xét một ví dụ.

class Animal {
   public void move() {
      System.out.println("Animals can move");
   }
}

class Dog extends Animal {
   public void move() {
      System.out.println("Dogs can walk and run");
   }
}

public class TestDog {

   public static void main(String args[]) {
      Animal a = new Animal();   // Animal reference and object
      Animal b = new Dog();   // Animal reference but Dog object

      a.move();   // runs the method in Animal class
      b.move();   // runs the method in Dog class
   }
}

Điều này sẽ tạo ra kết quả sau:

Đầu ra

Animals can move
Dogs can walk and run

Trong ví dụ trên, bạn có thể thấy rằng mặc dù blà một loại Động vật nó chạy phương thức di chuyển trong lớp Chó. Lý do cho điều này là: Trong thời gian biên dịch, việc kiểm tra được thực hiện trên kiểu tham chiếu. Tuy nhiên, trong thời gian chạy, JVM tìm ra loại đối tượng và sẽ chạy phương thức thuộc về đối tượng cụ thể đó.

Do đó, trong ví dụ trên, chương trình sẽ biên dịch đúng cách vì lớp Animal có phương thức di chuyển. Sau đó, trong thời gian chạy, nó chạy phương thức cụ thể cho đối tượng đó.

Hãy xem xét ví dụ sau:

Thí dụ

class Animal {
   public void move() {
      System.out.println("Animals can move");
   }
}

class Dog extends Animal {
   public void move() {
      System.out.println("Dogs can walk and run");
   }
   public void bark() {
      System.out.println("Dogs can bark");
   }
}

public class TestDog {

   public static void main(String args[]) {
      Animal a = new Animal();   // Animal reference and object
      Animal b = new Dog();   // Animal reference but Dog object

      a.move();   // runs the method in Animal class
      b.move();   // runs the method in Dog class
      b.bark();
   }
}

Điều này sẽ tạo ra kết quả sau:

Đầu ra

TestDog.java:26: error: cannot find symbol
      b.bark();
       ^
  symbol:   method bark()
  location: variable b of type Animal
1 error

Chương trình này sẽ gây ra lỗi thời gian biên dịch vì kiểu tham chiếu của b là Animal không có phương thức có tên là vỏ cây.

Quy tắc ghi đè phương pháp

  • Danh sách đối số phải giống hoàn toàn với danh sách của phương thức được ghi đè.

  • Kiểu trả về phải giống hoặc một kiểu con của kiểu trả về được khai báo trong phương thức ghi đè ban đầu trong lớp cha.

  • Cấp độ truy cập không thể hạn chế hơn cấp độ truy cập của phương thức bị ghi đè. Ví dụ: Nếu phương thức của lớp cha được khai báo là public thì phương thức ghi đè trong lớp con không thể là private hoặc protected.

  • Các phương thức phiên bản chỉ có thể được ghi đè nếu chúng được kế thừa bởi lớp con.

  • Không thể ghi đè phương thức được khai báo cuối cùng.

  • Một phương thức được khai báo static không thể bị ghi đè nhưng có thể được khai báo lại.

  • Nếu một phương thức không thể được kế thừa, thì nó không thể được ghi đè.

  • Một lớp con trong cùng một gói với lớp cha của cá thể có thể ghi đè lên bất kỳ phương thức lớp cha nào không được khai báo là private hoặc cuối cùng.

  • Một lớp con trong một gói khác chỉ có thể ghi đè các phương thức không phải là phương thức cuối cùng được khai báo công khai hoặc được bảo vệ.

  • Một phương thức ghi đè có thể ném bất kỳ ngoại lệ nào chưa được chọn, bất kể phương thức ghi đè có ném ngoại lệ hay không. Tuy nhiên, phương thức ghi đè không nên ném các ngoại lệ đã kiểm tra mới hoặc rộng hơn các ngoại lệ được khai báo bởi phương thức ghi đè. Phương thức ghi đè có thể đưa ra các ngoại lệ hẹp hơn hoặc ít hơn phương thức ghi đè.

  • Không thể ghi đè các trình xây dựng.

Sử dụng siêu từ khóa

Khi gọi một phiên bản siêu lớp của một phương thức được ghi đè, super từ khóa được sử dụng.

Thí dụ

class Animal {
   public void move() {
      System.out.println("Animals can move");
   }
}

class Dog extends Animal {
   public void move() {
      super.move();   // invokes the super class method
      System.out.println("Dogs can walk and run");
   }
}

public class TestDog {

   public static void main(String args[]) {
      Animal b = new Dog();   // Animal reference but Dog object
      b.move();   // runs the method in Dog class
   }
}

Điều này sẽ tạo ra kết quả sau:

Đầu ra

Animals can move
Dogs can walk and run