Đa hình tại Runtime trong Java

GIỚI THIỆU

Đa hình là khả năng của một đối tượng có thể nhận nhiều hình thái khác nhau. Cách dùng phổ biến của đa hình trong OOP là khi một tham chiếu của lớp cha được dùng để tham chiếu đến đối tượng của lớp con. Bất kỳ đối tượng nào trong Java đều mang tính chất đa hình do tất cả đối tượng đều được kế thừa từ lớp Object. Cách duy nhất để truy cập đến một đối tượng là thông qua biến tham chiếu. Một biến tham chiếu chỉ có thể có một kiểu, khi đã được khai báo, kiểu của một biến tham chiếu không thể thay đổi. Biến tham chiếu có thể được gán lại cho một đối tượng khác khi biến tham chiếu đó không phải là final. Kiểu của biến tham chiếu sẽ quyết định phương thức có thể gọi được từ đối tượng. Một biến tham chiếu có thể được xem như bất kỳ đối tượng nào thuộc cùng kiểu hoặc bất kỳ kiểu con của kiểu mà biến đó được khai báo.

KHÁI NIỆM VỀ ĐA HÌNH TẠI RUNTIME

Đa hình tại runtime trong Java là một tiến trình mà trong đó một lời gọi tới một phương thức được ghi đè sẽ được xử lý tại runtime thay vì tại compile time. Trong tiến trình này, một phương thức được ghi đè sẽ được gọi thông quan biến tham chiếu của một lớp cha. Việc quyết định phương thức được gọi dựa trên đối tượng được tham chiếu bởi biến tham chiếu. Trước khi tìm hiểu về đa hình tại runtime, chúng ta cùng tìm hiểu về Upcasting. Upcasting là khi biến tham chiếu của lớp cha tham chiếu tới đối tượng của lớp con, ví dụ:

class A{}  
class B extends A{}  
A a=new B();//day la upcasting 

VÍ DỤ

Trong ví dụ ta tạo hai lớp Bike và Splendar, lớp Splendar kế thừa lớp Bike và ghi đè phương thức run() của nó. Chúng ta gọi phương thức run bằng biến tham chiếu của lớp cha. Khi nó tham chiếu tới đối tượng của lớp con và phương thức lớp con ghi đè phương thức của lớp cha, phương thức của lớp con được triệu hồi tại runtime. Việc gọi phương thức được quyết định bởi JVM chứ không phải Compiler.

class Bike{  
  void run(){System.out.println("dang chay");}  
}  
class Splender extends Bike{  
  void run(){System.out.println("chay an toan voi 60km");}  
  
  public static void main(String args[]){  
    Bike b = new Splender(); 
    b.run();  // chay an toan voi 60km
  }  
}  

ĐA HÌNH TẠI RUNTIME TRONG JAVA VỚI THUỘC TÍNH

Phương thức bị ghi đè không phải là thuộc tính, vì thế đa hình tại runtime không hoạt động với thuộc tính. Cùng xem ví dụ dưới đây:

class Bike{  
 int speedlimit=90;  
}  
class Honda3 extends Bike{  
 int speedlimit=150;  
  
 public static void main(String args[]){  
  Bike obj=new Honda3();  
  System.out.println(obj.speedlimit);//90  
}  

Cả hai lớp đều có một thuộc tính là speedlimit, chúng ta có thể truy cập nó bằng cách sử dụng tham chiếu của lớp cha tham chiếu vào đối tượng của lớp con, nhưng khi truy cập thuộc tính đó nó sẽ không bị ghi đè mà kết quả in ra vẫn là giá trị thuộc tính của lớp cha.

ĐA HÌNH TẠI RUNTIME TRONG JAVA VỚI KẾ THỪA NHIỀU TẦNG

Cùng theo dõi ví dụ bên dưới về kế thừa nhiều tầng

class Animal{  
  void eat(){System.out.println("an");}  
}  
class Dog extends Animal{  
  void eat(){System.out.println("an hoa qua");}  
}  
class BabyDog extends Dog{  
  public static void main(String args[]){  
    Animal a1,a2,a3;  
    a1=new Animal();  
    a2=new Dog();  
    a3=new BabyDog();  
  
    a1.eat();  // an
    a2.eat();  // an hoa qua
    a3.eat();  // an hoa qua
}  
}  

Trong ví dụ trên, lớp Dog kế thừa lớp Animal và ghi đè phương thức eat() của lớp Animal. Lớp BabyDog kế thừa lớp Dog nhưng không ghi đè phương thức eat(). Khi gọi phương thức eat() từ tham chiếu của lớp BabyDog, phương thức eat() của lớp Dog sẽ được gọi đến.

KẾT LUẬN

  • Sử dụng Override bản chất là đa hình tại runtime
  • Việc gọi phương thức khi override được quyết định bở JVM chứ không phải Compiler
  • Không thể áp dụng đa hình tại runtime với các thuộc tính chứa dữ liệu
  • Việc gọi phương thức của một lớp kế thừa lớp khác nếu không ghi đè phương thức của lớp cha thì phương thức đó sẽ được gọi từ lớp cha được kế thừa trực tiếp

Tài liệu tham khảo:

Đa hình trong Java