Override và Overload là hai kỹ thuật quan trọng trong Java để thực hiện tính đa hình, một khái niệm quan trọng trong lập trình hướng đối tượng. Do có nhiều sự tương đồng nên khiến các bạn dễ nhầm lẫn. Trong bài viết này, mình sẽ làm rõ điểm khác biệt giữa override và overload giúp các bạn ứng dụng hiệu quả trong lập trình nhé!
Tính đa hình trong Java
Tính đa hình trong Java (polymorphism) là một trong bốn đặc tính cơ bản của lập trình hướng đối tượng (OOP) bên cạnh tính kế thừa (inheritance), tính đóng gói (encapsulation) và tính trừu tượng (abstraction). Tính đa hình cho phép một đối tượng có thể nhận nhiều hình thái khác nhau, giúp tăng tính linh hoạt và tái sử dụng code. Để đạt tính đa hình trong Java, có thể sử dụng 2 phương thức gồm:
- Overloading (Nạp chồng)
- Overriding (Ghi đè)
Overload trong Java
Overload (nạp chồng) là việc định nghĩa nhiều phương thức cùng tên trong cùng một lớp nhưng có số lượng hoặc kiểu dữ liệu của tham số khác nhau. Khi gọi một phương thức bị nạp chồng, Java sẽ tự động chọn phương thức phù hợp dựa trên kiểu dữ liệu và số lượng tham số truyền vào.
Quy tắc định nghĩa overload:
- Các phương thức cùng tên nhưng phải khác tham số (số lượng hoặc kiểu dữ liệu).
- Phạm vi truy cập (access modifier), kiểu trả về (return type) và ngoại lệ (exceptions) không ảnh hưởng đến quy tắc overload.
Override trong Java
Override (ghi đè) là việc lớp con ghi đè phương thức của lớp cha, thay đổi cách thức thực hiện của phương thức đó. Khi gọi một phương thức đã được ghi đè, phương thức của lớp con sẽ được ưu tiên thực thi thay vì phương thức của lớp cha.
Quy tắc định nghĩa override:
- Phương thức của lớp con phải cùng tên, cùng tham số và cùng kiểu trả về với phương thức của lớp cha.
- Phạm vi truy cập (access modifier) của phương thức lớp con phải rộng hơn hoặc bằng phạm vi truy cập của phương thức lớp cha.
- Nếu phương thức lớp cha ném ra ngoại lệ (throws exception), phương thức lớp con chỉ được phép ném ra các ngoại lệ con của ngoại lệ lớp cha hoặc không ném ra ngoại lệ.
Sự khác biệt giữa Override và Overload
So sánh và giải thích sự khác biệt về cú pháp, tham số và kết quả trả về của Override và Overload
Điểm khác biệt | Override | Overload |
Tên phương thức | Giống với phương thức được ghi đè | Khác với tên phương thức gốc |
Tham số | Giống với phương thức được ghi đè | Khác với tham số của phương thức gốc |
Kiểu trả về | Giống với phương thức được ghi đè | Có thể giống hoặc khác với kiểu trả về của phương thức gốc |
Modifier | Phải có cùng hoặc phạm vi phương thức trên | Không cần phải có cùng hoặc phạm vi phương thức trên |
Thứ tự phương thức được gọi | Phương thức được ghi đè được gọi | Phương thức tải được gọi dựa trên tham số được truyền vào |
Đối tượng được gọi | Phương thức trong lớp con được gọi | Phương thức được gọi phụ thuộc vào số lượng và kiểu tham số được truyền vào |
Kiểu trả về | Phương thức được ghi đè phải có cùng kiểu trả về như phương thức được ghi đè | Phương thức được nạp chồng có thể có kiểu trả về khác nhau |
Quá trình biên dịch | Ghi đè được xác định trong quá trình biên dịch | Nạp chồng được xác định trong quá trình biên dịch và thời gian chạy |
Mục đích sử dụng | Ghi đè thường được sử dụng để triển khai lại phương thức của lớp cha để cung cấp cài đặt tùy chỉnh cho phương thức đó | Nạp chồng thường được sử dụng để cung cấp nhiều cách để gọi cùng một phương thức với các tham số khác nhau |
Ví dụ minh họa
Để hiểu rõ hơn sự khác biệt thực tế giữa overload và override trong Java, chúng ta hãy cùng xem ví dụ sau đây:
public class Shape {
// Tạo lớp Shape với phương thức draw() đơn giản in ra chuỗi “Drawing a shape”.
public void draw() {
System.out.println(“Drawing a shape”);
}
}
public class Circle extends Shape {
// Ghi đè phương thức draw() để in ra chuỗi “Drawing a circle”.
@Override
public void draw() {
System.out.println(“Drawing a circle”);
}
// Nạp chồng phương thức draw() để in ra chuỗi “Drawing a circle with radius X”.
public void draw(int radius) {
System.out.println(“Drawing a circle with radius ” + radius);
}
}
public class Main {
public static void main(String[] args) {
// Tạo đối tượng Shape và Circle.
Shape shape = new Shape();
Circle circle = new Circle();
// Gọi phương thức draw() trên đối tượng Shape.
shape.draw(); // Output: Drawing a shape
// Gọi phương thức draw() trên đối tượng Circle.
circle.draw(); // Output: Drawing a circle
// Gọi phương thức draw() với tham số trên đối tượng Circle.
circle.draw(5); // Output: Drawing a circle with radius 5
}
}
Ta có lớp cha Shape và lớp con Circle. Lớp Shape có một phương thức draw() đơn giản, trong khi lớp Circle có hai phương thức draw(), một phương thức được ghi đè (overriding method) và một phương thức được nạp chồng (overloading method).
- Override: Phương thức draw() trong lớp Circle được ghi đè lại (override) từ phương thức draw() trong lớp Shape. Khi phương thức draw() được gọi trên đối tượng Circle, phương thức draw() trong lớp Circle sẽ được gọi thay vì phương thức draw() trong lớp Shape.
- Overload: Lớp Circle có một phương thức draw() khác với tham số là radius. Khi phương thức draw() được gọi trên đối tượng Circle với tham số là radius, phương thức draw() với tham số radius sẽ được gọi thay vì phương thức draw() được ghi đè từ lớp Shape.
Lợi ích của Override và Overload trong Java
Override và Overload đóng vai trò quan trọng trong việc phát triển tính đa hình:
- Override giúp thực hiện tính đa hình thông qua việc kế thừa và thay đổi hành vi của phương thức từ lớp cha.
- Overload giúp thực hiện tính đa hình khi kết hợp với Override, cho phép tạo ra nhiều phương thức với cùng một tên nhưng khác nhau về số lượng hoặc kiểu dữ liệu của tham số.
Sử dụng Override và Overload giúp tăng tính linh hoạt và tái sử dụng code:
- Tính linh hoạt: Override và Overload giúp dễ dàng điều chỉnh và thay đổi hành vi của phương thức mà không cần thay đổi tên phương thức. Điều này giúp giảm thiểu sự rắc rối trong quá trình lập trình và giúp code dễ đọc hơn.
- Tái sử dụng code: Override cho phép lớp con kế thừa và thay đổi hành vi của phương thức từ lớp cha, giúp giảm thiểu việc lặp lại code và tận dụng tốt hơn các phương thức đã có sẵn. Overload giúp tạo ra nhiều phương thức với cùng một tên nhưng khác nhau về số lượng hoặc kiểu dữ liệu của tham số, từ đó giúp giảm thiểu việc phải tạo ra nhiều phương thức khác nhau cho cùng một chức năng.
Kết luận
Override và Overload là hai kỹ thuật quan trọng trong Java để thực hiện tính đa hình và tăng tính linh hoạt và tái sử dụng code. Sự khác nhau giữa hai kỹ thuật này cho phép chúng ta áp dụng chúng vào các tình huống khác nhau trong quá trình phát triển phần mềm. Hy vọng bài viết này đã giúp bạn hiểu rõ hơn về Override và Overload trong Java.
Để lại một phản hồi
Bạn phải đăng nhập để gửi phản hồi.