Ghi đè trong Java – Go Coding

Ghi đè trong Java

Ghi đè là một khái niệm cốt lõi của Lập trình hướng đối tượng và được liên kết trực tiếp với tính năng Kế thừa. Ghi đè là một tính năng cho phép các lớp con triển khai các chức năng cho các phương thức cùng tên của chính nó với tên của lớp siêu của nó. Nói một cách đơn giản hơn, nếu một phương thức đã được định nghĩa trong lớp siêu, khi một lớp con mở rộng nó, nó có thể khai báo một phương thức có cùng tên và phương thức mới được hình thành trong lớp con sẽ được gọi trong khi gọi phương thức. Ghi đè trong Java được định nghĩa là xảy ra ‘khi một phương thức trong lớp con có cùng tên, cùng tham số hoặc chữ ký và cùng kiểu trả về (hoặc kiểu con) như một phương thức trong lớp siêu của nó’. Phương thức của lớp con ghi đè phương thức của lớp cha.

Ví dụ: Mã giả

Animal (Parent Class) {data .. move () // Phương thức của lớp cha eat () // Phương thức của lớp cha} Dog extension Animal {data .. move () // Ghi đè phương thức move () của lớp cha . sủa () // Phương thức của lớp con

 

Tính năng ghi đè phương thức thường được sử dụng để đạt được tính đa hình Thời gian chạy của Java. Trong lớp phương thức, phiên bản nào của phương thức sẽ được gọi sẽ chỉ phụ thuộc vào kiểu đối tượng, đó là đối tượng của lớp cha hay lớp con. Nếu một đối tượng của lớp cha được sử dụng để gọi phương thức, thì phiên bản lớp cha của phương thức sẽ được gọi. Nếu một đối tượng của lớp con được sử dụng để gọi phương thức, thì phương thức lớp con sẽ được gọi ghi đè phiên bản lớp cha. Do đó, thay vì kiểu của biến tham chiếu, nó là kiểu của đối tượng được sử dụng để xác định phương thức nào sẽ được gọi và phương thức nào sẽ bị ghi đè.

Mã mẫu

Đoạn mã sau đây sẽ trình bày một ví dụ đơn giản về ghi đè phương thức.

// Lớp cha lớp Parent {void show () {System.out.println (“Parent's show ()”); }} // Lớp con lớp Con mở rộng Parent {@override void show () {System.out.println (“Chương trình con”); }} // Lớp Main Class lớp Main {public static void main (String args []) {Parent obj1 = new Parent (); obj1.show (); Parent obj2 = new Child (); obj2.show (); }}

 

OUTPUT

Chương trình của cha mẹ
Chương trình của trẻ em

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

1. Công cụ sửa đổi ghi đè và truy cập

Không có cách nào mà công cụ sửa đổi quyền truy cập có thể giảm phạm vi cho một phương thức ghi đè. Tuy nhiên, nó có thể cho phép phạm vi lớn hơn nếu được chọn phù hợp. Ví dụ: nếu bạn có một phương thức thể hiện được bảo vệ trong lớp siêu, bạn có thể đặt nó ở chế độ công khai trong lớp con nhưng bạn không thể đặt nó ở chế độ riêng tư. Do đó, bạn không thể giảm thêm phạm vi và chỉ hạn chế nó ở lớp hiện tại. Điều này sẽ dẫn đến lỗi thời gian biên dịch.

Mã mẫu

class Parent {private void m1 () {System.out.println (“Từ cha m1 ()”); } protected void m2 () {System.out.println (“Từ m2 mẹ ()”); }} lớp Con mở rộng Parent {private void m1 () {System.out.println (“Từ Con m1 ()”); } @Override public void m2 () {System.out.println (“Từ con m2 ()”); }} // Lớp Main Class Lớp Main {public static void main (String args []) {Parent obj1 = new Parent (); obj1.m2 (); Parent obj2 = new Child (); obj2.m2 (); }}

 

OUTPUT
Từ m2 mẹ ()
Từ con m2 ()

2. Phương thức cuối cùng không thể được ghi đè

Bất kỳ phương thức nào có bee được khai báo cuối cùng trong lớp siêu, không thể được ghi đè trong lớp con. Đây cũng có thể được coi là một kỹ thuật bạn có thể thực hiện khi bạn không muốn một phương thức cụ thể trong lớp siêu bị ghi đè trong lớp con.

// Một đoạn mã mẫu để chỉ ra rằng các phương thức cuối cùng không thể bị ghi đè lên lớp Parent {final void show () {}} class Con expand Parent {void show () {}}

 

OUTPUT

13: error: show () trong Con không thể ghi đè show () trong Cha
void show () {}
phương pháp ghi đè là cuối cùng

 

3. Phương thức tĩnh không thể bị ghi đè

Điều này đưa chúng ta đến sự khác biệt giữa ghi đè phương thức và ẩn phương thức. Khi một phương thức tĩnh được định nghĩa với cùng một danh sách, chữ ký và đối số của một siêu lớp, tính năng này được gọi là ẩn phương thức chứ không phải ghi đè. Bảng sau đây tóm tắt việc ghi đè tốt hơn:

 
Phương pháp phiên bản siêu lớp
Phương pháp tĩnh siêu lớp

Phương pháp phiên bản lớp con
Ghi đè
Tạo lỗi thời gian biên dịch

Phương pháp tĩnh lớp con
Tạo lỗi thời gian biên dịch
Phương thức ẩn diễn ra.

 

class Parent {static void m1 () {System.out.println (“Từ cha” + “static m1 ()”); } void m2 () {System.out.println (“Từ cha” + “non-static (instance) m2”); }} lớp Con mở rộng Parent {static void m1 () {System.out.println (“Từ con static m1 ()”); } // Phương thức này ghi đè m2 của lớp cha @Override public void m2 () {System.out.println (“Từ con” + “non static (instance) m2 ()”); }} // Lớp main class Main {public static void main (String args []) {Parent obj1 = new Child (); obj1.m1 (); obj1.m2 (); }}

 

OUTPUT
Từ tĩnh mẹ m1 ()
Từ con non-static (instance) m2 ()

4. Không thể ghi đè các phương thức riêng tư

Công cụ sửa đổi quyền truy cập riêng tư giới hạn phạm vi của các thực thể chương trình chỉ đối với thực thể cụ thể đó. Do đó, không thể ghi đè một phương thức private trong một lớp con vì phạm vi của phương thức sẽ chỉ tồn tại bên trong lớp cha.

5. Phương thức ghi đè phải có cùng kiểu trả về hoặc kiểu con

Trong một thời gian dài, Java không cho phép các lớp con ghi đè một phương thức của lớp cha có kiểu trả về khác. Tuy nhiên, từ Java 5.0, các phương thức ghi đè trong lớp con có thể có kiểu trả về khác với phương thức được ghi đè nhưng nó phải là kiểu con của kiểu trả về của phương thức được ghi đè. Đây cũng được gọi là kiểu trả về hiệp phương sai.

6. Gọi phương thức ghi đè từ lớp con

Nếu bạn muốn gọi cụ thể phương thức được ghi đè của lớp cha từ lớp con, bạn có thể thực hiện việc này bằng cách sử dụng từ khóa super như sau:

class Parent {void show () {System.out.println (“Parent's show ()”); }} class Con mở rộng Parent {@Override void show () {super.show () System.out.println (“Chương trình con ()”); }} // Lớp Main Class lớp Main {public static void main (String args []) {Parent obj = new Child (); obj.show (); }}

 

OUTPUT

Chương trình của cha mẹ
Chương trình của trẻ em

7. Ghi đè khối lệnh

Hàm tạo của lớp siêu không bao giờ có thể bị ghi đè trong lớp con. Điều này là do hàm tạo là duy nhất cho mọi lớp và có tên của lớp trong khai báo của nó. Vì các lớp con có tên khác nhau, điều đó là không thể.

8. Ghi đè và ngoại lệ – Xử lý

Có hai quy tắc thích hợp để xử lý ngoại lệ khi nói đến ghi đè phương thức. Chúng như sau:

  1. Quy tắc 1: Khi phiên bản siêu lớp của phương thức không ném ra bất kỳ ngoại lệ nào, ngoại lệ duy nhất mà phương thức ghi đè có thể ném là ngoại lệ không được kiểm tra. Nó không thể ném một ngoại lệ đã kiểm tra vì điều đó sẽ dẫn đến lỗi thời gian biên dịch.
    class Parent {void m1 () {out.println (“Từ cha mẹ m1 ()”); } void m2 () {System.out.println (“Từ m2 mẹ ()”); }} class Con mở rộng Parent {@Override void m1 () ném ArithmeticException {System.out.println (“Từ con m1 ()”); } @override void m2 () ném Exception {System.out.println (“Từ m2 con”); }}

     

    OUTPUT
    lỗi: m2 () trong con không thể ghi đè m2 () trong Cha
    void m2 () ném Exception {System.out.println (“Từ m2 con”)}
    phương thức ghi đè không ném Ngoại lệ

  2. Quy tắc 2: Nếu trong trường hợp phương thức ghi đè trong lớp cha ném ra một ngoại lệ, thì phương thức ghi đè trong lớp con chỉ có thể ném cùng một ngoại lệ của lớp con đó. Nếu nó ném một ngoại lệ cha trong cấu trúc phân cấp Ngoại lệ, lỗi thời gian biên dịch sẽ gặp phải. Trường hợp tốt nhất là khi phiên bản lớp con của phương thức không ném ra bất kỳ ngoại lệ nào.
    class Parent {void m1 () ném RunTimeException {out.println (“Từ cha mẹ m1 ()”); }} lớp Child1 mở rộng Parent {@Override void m1 () ném RuntimeException {System.out.println (“Từ con m1 ()”); } class Child2 expand Parent {@Override void m1 () ném ArithmeticException {System.out.osystemln (“From child2 m1 ()”); }} lớp Child3 mở rộng Parent {@Override void m1 () {System.out.println (“Từ child3 m1 ()”); }} class Child4 mở rộng Parent {@Override void m1 () ném Exception {System.out.println (“Từ child4 m1 ()”); }}

     

    OUTPUT
    lỗi: m1 () trong child4 không thể ghi đè m1 () trong Parent
    void m1 () ném Ngoại lệ
    phương thức ghi đè không ném Ngoại lệ

9. Phương pháp ghi đè và tóm tắt

Các phương thức trừu tượng thường là các khai báo phương thức mà không có bất kỳ phần thân phương thức nào quan trọng. Các phương thức của các loại này thường được ghi đè trong lớp con. Nói cách đơn giản hơn, các phương thức trừu tượng được chứa trong lớp cha mà sau đó được ghi đè trong các lớp con, nếu không, mã sẽ gặp phải lỗi thời gian biên dịch.

10. Ghi đè và phương thức đồng bộ / nghiêm ngặt

Các phương thức đồng bộ / nghiêm ngặt không có bất kỳ ảnh hưởng nào đến các quy tắc ghi đè. Do đó, phương thức đồng bộ / nghiêm ngặt có thể ghi đè phương thức không đồng bộ / nghiêm ngặt.

Mã mẫu để hiển thị ghi đè phương pháp đa cấp

class Parent {void show () {System.out.println (“show của cha ()”); }} class Chilld expand Parent {void show () {System.out.println (“Child's show ()”); } class Grandchild Extended Child {void show () {System.out.println (“Grandchild's show ()”); }} // Lớp main class Main {public static void main (String args []) {Parent obj1 = new Grandchild (); đối tượng1. buổi bieu diễn (); }}

 

OUTPUT
Chương trình của cháu ()

Ghi đè so với quá tải

  • Quá tải đề cập đến việc khai báo nhiều hơn một phương thức có cùng tên phương thức nhưng danh sách tham số khác nhau. Trong khi việc ghi đè giao dịch với các phương thức khác nhau, việc ghi đè các giao dịch với cùng một phương thức được ghi đè trong một lớp con được kết nối thông qua kế thừa.
  • Quá tải là một ví dụ về đa hình thời gian biên dịch trong khi ghi đè là một ví dụ về đa hình thời gian chạy.

Tại sao phải ghi đè phương pháp?

Như đã đề cập ở trên, ghi đè phương thức cho phép Java thực hiện đa hình thời gian chạy. Tính đa hình là một phần rất quan trọng của Java vì nó cung cấp cho người dùng tùy chọn để khai báo các phương thức trong một lớp siêu và chỉ định các chức năng trong các lớp con. Khái niệm ‘một giao diện, nhiều phương thức’ là một dẫn xuất trực tiếp của việc ghi đè phương thức.

Để kích hoạt khả năng tái sử dụng và độ mạnh của mã, Java sử dụng một công cụ rất mạnh gọi là Dynamic Method Dispatch. Khả năng các thư viện mã hiện có để gọi các phương thức trên các phiên bản của các lớp mới được tạo là một lợi ích rất lớn đối với ngôn ngữ lập trình.

Một ưu điểm chính của việc áp dụng kỹ thuật ghi đè phương thức này là nó cho phép chúng ta gọi các phương thức mà không cần biết loại phương thức trong các đối tượng dẫn xuất đang được sử dụng để gọi các phương thức ngay từ đầu.

Khi nào thì áp dụng ghi đè?

Chìa khóa để sử dụng phương thức ghi đè đúng cách là hiểu động lực của sự kế thừa bao gồm một siêu lớp được mở rộng hoặc kế thừa bởi một lớp con. Luồng kế thừa chuyển từ chuyên môn hóa thấp hơn trong các lớp cha sang các chuyên môn hóa lớn hơn trong các lớp con. Mục đích chính phải là sao cho lớp mẹ có tất cả các nguyên liệu cần thiết để nấu một món ăn cụ thể. Lớp con sẽ sử dụng các nguyên liệu từ lớp siêu cấp để nấu món ăn mà nó muốn theo phương pháp riêng của nó.