Polymorphism ("nhiều hình thức") — cùng interface có nhiều cách hành xử. Java có 2 loại:
1. Compile-time — Method overloading: cùng tên, khác signature → compiler chọn lúc biên dịch.
class Calculator {
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
}**2.
Runtime — Method overriding: subclass có version riêng → JVM dispatch theo kiểu thực** của object.
class Animal { void speak() {} }
class Dog extends Animal { @Override void speak() { System.out.println("Woof"); } }
Animal a = new Dog();
a.speak(); // "Woof" — theo kiểu thực, không theo referenceLợi ích của runtime polymorphism — nền tảng của OOP linh hoạt:
- Open/Closed: thêm subtype mới không sửa code dùng nó.
- Decoupling: phụ thuộc abstraction (Animal) thay vì concrete (Dog).
- Nền tảng của DI, Strategy, Template, Factory pattern.
interface PaymentGateway { void charge(BigDecimal amount); }
class Checkout {
private final PaymentGateway gw; // không biết là Stripe hay Paypal
Checkout(PaymentGateway gw) { this.gw = gw; }
}Lưu ý:
- static method không override — chỉ hide (theo reference type).
- private, final method không override được.
- Field không polymorphic — đọc theo kiểu reference, không theo object. Chỉ method mới dynamic dispatch.
Polymorphism ("many forms") — the same interface behaves in many ways. Java has two kinds:
1. Compile-time — Method overloading: same name, different signatures → compiler picks at compile time.
class Calculator {
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
}**2.
Runtime — Method overriding: the subclass has its own version → the JVM dispatches by the actual** object type.
class Animal { void speak() {} }
class Dog extends Animal { @Override void speak() { System.out.println("Woof"); } }
Animal a = new Dog();
a.speak(); // "Woof" — by actual type, not the referenceBenefits of runtime polymorphism — bedrock of flexible OOP:
- Open/Closed: add new subtypes without touching client code.
- Decoupling: depend on the abstraction (Animal) instead of the concrete (Dog).
- Underpins DI, Strategy, Template, Factory patterns.
interface PaymentGateway { void charge(BigDecimal amount); }
class Checkout {
private final PaymentGateway gw; // could be Stripe or Paypal
Checkout(PaymentGateway gw) { this.gw = gw; }
}Caveats:
- static methods are not overridden — only hidden (by reference type).
- private, final methods cannot be overridden.
- Fields are not polymorphic — read by reference type, not actual type. Only methods are dynamically dispatched.