Overload là gì ?
Overload – Nạp chồng phương thức đơn giản là có vài phương thức trùng tên nhưng khác nhau về đối số. Cài chồng phương thức cho phép ta tạo nhiều phiên bản của một phương thức, mỗi phiên bản chấp nhận một danh sách đối số khác nhau, nhằm tạo thuận lợi cho việc gọi phương thức. Nạp chồng phương thức Overload được sử dụng để thu được tinh đa hình tại compile time.
Ví dụ:
class Calculation { void sum(int a, int b) { System.out.println(a + b); } void sum(int a, int b, int c) { System.out.println(a + b + c); } }
Các cách nạp chồng overload
Thay đổi số lượng tham số
Ví dụ:
class Sum { void sum(int a, int b) { System.out.println(a + b); } void sum(int a, int b, int c) { System.out.println(a + b + c); } }
Thay đổi kiểu trả về của tham số
Ví dụ:
class Sum { void sum(int a, int b) { System.out.println(a + b); } void sum(int a, double b) { System.out.println(a + b); } }
Tự động ép kiểu trong nạp chồng
-
Kiểu dữ liệu của đối số truyền vào được thay đổi sang kiểu dữ liệu khác (tự động ép kiểu) nếu giá trị của đối số đó không phù hợp với kiểu dữ liệu của tham số đã được đinh nghĩa.
- Ví dụ phương thức sum(int x, double y) ở ví dụ trên khi được truyền tham số như sau sum(10, 20) thì giá trị tham số thứ 2 được truyền vào là int sẽ được tự động ép kiểu sang kiểu double.
- Quy tắc ép kiểu: Được tự động ép về kiểu dữ liệu lớn hơn và ưu tiên gần nhất kiểu dữ liệu được ép theo thứ tự hình sau:
- Theo hình trên thì kiểu byte có thể ép sang các kiểu lớn hơn nó như short, int, float, long, double nhưng nó sẽ ưu tiên kiểu short. Hoặc kiểu int có thể ép sang kiểu float, long, double nhưng nó sẽ ưu tiên ép sang kiểu long vì long gần nó hơn so với 2 kiểu còn lại.
Ví dụ:
class Sum { void sum(float a, float b) { System.out.println(“First method will be call”); } void sum(long a, long b) { System.out.println(“Second method will be call”); } public static void main(String[] args) { Sum s = new Sum(); s.sum(10, 20); } }
- Kết quả in ra sẽ là “Second method will be call” tức là hàm sum thứ 2 sẽ được gọi vì tham số truyền vào là kiểu int, nó sẽ ưu tiên ép sang kiểu lớn hơn nó và có giá trị gần nhất nó, ở đây là kiểu long.
- Từ đó ta có ta có thể suy ra là kiểu double không thể tự động ép kiểu.
Nạp chồng phương thức khởi tạo
- Xét trường hợp ta có các hàm khởi tạo chồng với hoạt động khởi tạo giống nhau và chỉ khác nhau ở phần xử lý các kiểu đối số. Ta sẽ không muốn chép đi chép lại phần mã khởi tạo mà các hàm khởi tạo đều có.
-
Cách giải quyết: ta sẽ đặt toàn bộ phần mã đó vào chỉ một trong các hàm khởi tạo. Và ta muốn rằng hàm khởi tạo nào cũng đều gọi đến hàm khởi tạo kia để nó hoàn thành công việc khởi tạo. Để làm việc đó, ta dùng this() để gọi một hàm khởi tạo từ bên trong một hàm khởi tạo khác của cùng một lớp.
- Ví dụ:
public class Student { int id; String name; Student() { System.out.println(“gọi Constructor mặc định”); } Student(int id, String name) { this(); // nó được sử dụng để gọi Constructor của lớp hiện tại this.id = id; this.name = name; } void display() { System.out.println(id + ” ” + name); } public static void main(String args[]) { Student e1 = new Student(111, “Viet”); Student e2 = new Student(222, “Nam”); e1.display(); e2.display(); } }
- Kết quả in ra sẽ là:
- gọi Contructor mặc định
- gọi Contructor mặc định
- 111 Việt
- 222 Nam
Các quy tắc nạp chồng
- Các phương thức overloaded phải cùng tên nhưng khác nhau ở các tham số.
- Chúng có thể được định nghĩa cùng hoặc khác kiểu dữ liệu trả về.
- Chúng có thể được định nghĩa cùng hoặc khác access modifier.
- Các phương thức không được gọi là overloaded nếu chúng chỉ khác nhau ở kiểu dữ liệu trả về hoặc access modifier.
Override LÀ GÌ ?
Overriding là một tính 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 siêu hoặc các lớp cha của nó. Nói cách khác, nếu lớp con cung cấp trình triển khai cụ thể của phương thức mà đã được cung cấp bởi một trong các lớp cha của nó, thì đó là ghi đè phương thức.
Override được sử dụng để thu được tính đa hình tại runtime.
Gọi phiên bản phương thức của lớp cha
Có nhiều trường hợp khi cài đè 1 hành vi của lớp cha, nhưng ta lại không muốn thay thế hoàn toàn mà chỉ muốn bổ sung một số chi tiết.
-
Ví dụ: Chẳng hạn, lớp Account đại diện cho tài khoản ngân hàng chung chung. Nó cung cấp phương thức withdraw(double) với chức năng rút tiền, phương thức này thực hiện quy trình rút tiền cơ bản: trừ số tiền rút khỏi số dư tài khoản (balance). FeeBasedAccount là loại tài khoản ngân hàng thu phí đối với mỗi lần rút tiền, nghĩa là bên cạnh quy trình rút tiền cơ bản, nó còn làm thêm một việc là trừ phí rút tiền khỏi số dư tài khoản. Như vậy, FeeBasedAccount có cần đến nội dung của bản withdraw() được Account cung cấp sẵn, nhưng vẫn phải cài đè vì nội dung đó không đủ dùng. Ta cũng không muốn chép nội dung bản withdraw() của Account vào bản của FeeBasedAccount. Thay vào đó, ta muốn có cách gọi phương thức withdraw() của Account từ trong phiên bản cài đè tại FeeBasedAccount.
- Cách giải quyết: từ trong phiên bản cài đè tại lớp con, ta muốn gọi đến chính phương thức đó của lớp cha, từ khóa super cho phép gọi đến cách thành viên được thừa kế.
public class Account { private double balance = 0; public void deposit(double money) { balance += money; } public void wirhDraw(double money) { balance -= money; } public class FeeBasedAcount extends Account { private double fee = 10; public void withdraw(double money) { super.wirhDraw(money); balance -= fee; } } }
Các quy tắc cho việc cài đè
- Danh sách tham số phải trùng nhau, kiểu giá trị trả về phải tương thích.
- Phương thức đè không được giảm quyền truy nhập so với phiên bản của lớp cha.
- Nói cách khác, quyền truy nhập mà phiên bản của lớp con cho phép phải bằng hoặc rộng hơn phiên bản của lớp cha. Ta không thể cài đè một phương thức public bằng một phiên bản private. Nếu không, tình huống xảy ra là một lời gọi phương thức đã được trình biên dịch chấp nhận vì tưởng là phương thức public nhưng đến khi nó chạy lại bị máy ảo từ chối vì phiên bản được gọi lại là private.
- Phải là quan hệ IS-A (kế thừa).
- Các phương thức final, static, private không thể cài đè.
Sự khác nhau giữa overload và override
Override Overload Hành vi Thay đổi hành vi hiện tại của phương thức. Thêm hoặc mở rộng cho hành vi của phương thức. Đa hình Thể hiện tính đa hình tại run time. Thể hiện tính đa hình tại compile time. Danh sách tham số Danh sách tham số phải giống nhau. Danh sách tham số có thể khác nhau. Quyền truy cập Phương thức ghi đè ở lớp con phải có quyền truy cập bằng hoặc lớn hơn phương thức được ghi đè ở lớp cha. Các phương thức nạp chồng có thể có quyền truy cập khác nhau. Giá trị trả về Kiểu trả về bắt buộc phải giống nhau. Kiểu trả về có thể khác nhau. Phạm vi Xảy ra giữa 2 class có quan hệ kế thừa Xảy ra trong phạm vi cùng 1 class.