Đa hình (Polymorphism)
1. Đa hình là gì?
Phần tiêu đề “1. Đa hình là gì?”Đa hình (polymorphism) nghĩa là “nhiều hình dạng” - một biến khai báo kiểu lớp cha có thể tham chiếu đến đối tượng của bất kỳ lớp con nào, và khi gọi phương thức đã bị override, Java sẽ tự động chạy đúng phiên bản của lớp thực sự của đối tượng (không phải kiểu khai báo của biến):
public class Animal { void makeSound() { System.out.println("Một số âm thanh..."); }}
public class Dog extends Animal { @Override void makeSound() { System.out.println("Gâu gâu!"); }}
public class Cat extends Animal { @Override void makeSound() { System.out.println("Meo meo!"); }}Animal animal1 = new Dog(); // biến kiểu Animal, nhưng trỏ đến đối tượng DogAnimal animal2 = new Cat(); // biến kiểu Animal, nhưng trỏ đến đối tượng Cat
animal1.makeSound(); // Gâu gâu! - chạy phiên bản của Dog, không phải Animalanimal2.makeSound(); // Meo meo! - chạy phiên bản của CatĐây gọi là runtime polymorphism (đa hình lúc chạy) - phương thức thực sự được gọi chỉ xác định lúc chương trình chạy, dựa trên lớp thực sự của đối tượng.
2. Lợi ích: viết code dùng chung cho nhiều loại đối tượng
Phần tiêu đề “2. Lợi ích: viết code dùng chung cho nhiều loại đối tượng”public static void makeAllSounds(Animal[] animals) { for (Animal animal : animals) { animal.makeSound(); // gọi ĐÚNG phiên bản tương ứng với từng đối tượng thực sự }}
Animal[] zoo = { new Dog(), new Cat(), new Dog() };makeAllSounds(zoo);// Gâu gâu!// Meo meo!// Gâu gâu!makeAllSounds không cần biết trước có bao nhiêu loại Animal con - chỉ cần mỗi lớp con tự override makeSound() đúng cách.
3. Biến kiểu lớp cha chỉ “thấy” những gì lớp cha khai báo
Phần tiêu đề “3. Biến kiểu lớp cha chỉ “thấy” những gì lớp cha khai báo”Dù animal1 thực sự trỏ đến một Dog, biến animal1 (khai báo kiểu Animal) chỉ gọi được các phương thức có khai báo trong Animal - không gọi trực tiếp được phương thức riêng chỉ có ở Dog:
public class Dog extends Animal { @Override void makeSound() { System.out.println("Gâu gâu!"); }
void fetch() { System.out.println("Đang nhặt bóng..."); } // riêng của Dog}
Animal animal = new Dog();animal.makeSound(); // OK - có trong Animal// animal.fetch(); // LỖI BIÊN DỊCH! fetch() không có trong Animal, dù đối tượng thực sự là DogMuốn gọi fetch(), cần ép kiểu tường minh: ((Dog) animal).fetch(); (cẩn thận ClassCastException nếu đối tượng không thực sự là Dog).
4. Đa hình qua interface
Phần tiêu đề “4. Đa hình qua interface”Đa hình cũng hoạt động tương tự với interface - một biến kiểu interface có thể trỏ đến bất kỳ lớp nào implement interface đó (xem trang “Interface và Abstract class”).
Tổng kết
Phần tiêu đề “Tổng kết”- Đa hình: biến kiểu lớp cha có thể trỏ đến đối tượng lớp con, tự động gọi đúng phiên bản phương thức đã override lúc chạy chương trình
- Cho phép viết code dùng chung, xử lý nhiều loại đối tượng con khác nhau qua cùng một kiểu tham chiếu
- Biến kiểu lớp cha chỉ gọi được các phương thức khai báo trong lớp cha (hoặc interface), trừ khi ép kiểu tường minh