Đa hình (Polymorphism) là khả năng thực hiện một hành động theo nhiều cách khác nhau. Java hỗ trợ 2 loại:
1. Compile-time Polymorphism (Static Binding / Early Binding)
- Còn gọi: Method Overloading (Nạp chồng phương thức).
- Quyết định phương thức nào được gọi tại thời điểm compile dựa trên signature (tên + tham số).
- Không liên quan đến inheritance.
- Static binding – JVM biết chính xác method nào chạy.
2. Runtime Polymorphism (Dynamic Binding / Late Binding)
- Còn gọi: Method Overriding (Ghi đè phương thức).
- Quyết định phương thức nào được gọi tại thời điểm chạy dựa trên object thực tế (runtime type).
- Yêu cầu Inheritance (kế thừa) hoặc Interface implementation.
- Dynamic binding – JVM tra bảng phương thức ảo (v-table) lúc chạy.
Bảng so sánh
| Tiêu chí | Compile-time (Overloading) | Runtime (Overriding) |
|---|---|---|
| Cơ chế | Static binding | Dynamic binding |
| Kế thừa | Không cần | Bắt buộc (extends/implements) |
| Signature | Khác nhau (tham số: số lượng, kiểu, thứ tự) | Giống hệt nhau (tên, tham số, return type) |
| Return type | Có thể khác nhau | Phải cùng kiểu hoặc covariant (subtype) |
| Access modifier | Tự do | Không hẹp hơn (protected ≥ default ≥ private) |
| Ví dụ điển hình | print(int), print(String), print(Object) | Animal.sound() → Dog.sound(), Cat.sound() |
Ví dụ Compile-time Polymorphism (Overloading)
public class CompileTimePoly {
// Overload: khác tham số
void display() {
System.out.println("Không tham số");
}
void display(String msg) {
System.out.println("Có tham số: " + msg);
}
void display(int a, int b) {
System.out.println("Hai số: " + a + ", " + b);
}
public static void main(String[] args) {
CompileTimePoly obj = new CompileTimePoly();
obj.display(); // Gọi version 1
obj.display("Hello"); // Gọi version 2
obj.display(10, 20); // Gọi version 3
}
}
Ví dụ Runtime Polymorphism (Overriding)
class Animal {
public void sound() {
System.out.println("Animal makes sound");
}
}
class Dog extends Animal {
@Override
public void sound() {
System.out.println("Dog barks: Gâu gâu");
}
}
class Cat extends Animal {
@Override
public void sound() {
System.out.println("Cat meows: Meo meo");
}
}
public class RuntimePoly {
public static void main(String[] args) {
Animal a1 = new Dog(); // Reference Animal, Object Dog
Animal a2 = new Cat(); // Reference Animal, Object Cat
a1.sound(); // Runtime: gọi Dog.sound() → "Dog barks"
a2.sound(); // Runtime: gọi Cat.sound() → "Cat meows"
// Có thể dùng mảng/collection Animal chứa nhiều subclass
Animal[] animals = {new Dog(), new Cat(), new Animal()};
for (Animal a : animals) a.sound();
}
}
Tóm tắt
- Overloading = cùng class, khác signature → compile-time.
- Overriding = parent-child, cùng signature → runtime.
- Java dùng dynamic method dispatch cho overriding – nền tảng của OOP linh hoạt.
@Overrideannotation giúp compile-time check lỗi overriding (sai signature, final method...).