Trong bài Ép kiểu trong Java tôi đã giới thiệu với các bạn chuyển kiểu đối với kiểu dữ liệu cơ bản. Trong bài này, tôi sẽ giới thiệu với các bạn cơ chế Upcasting và Downcasting trong java. Đây là cơ chế được sử dụng để chuyển kiểu đối với kiểu dữ liệu tham chiếu.
Ví dụ chương trình sau:
class Animal { public void eat() { System.out.println("eating..."); } } public class Cat extends Animal { public void meow() { System.out.println("meowing..."); } }
Nội dung
Upcasting
Khi biến tham chiếu của lớp cha tham chiếu tới đối tượng của lớp con, thì đó là Upcasting.
Ví dụ:
public class Upcasting { public static void main(String[] args) { Cat cat = new Cat(); Animal animal1 = cat; // Chuyển kiểu không tường minh Animal animal2 = (Animal) cat; // Chuyển kiểu tường minh cat.eat(); cat.meow(); animal1.eat(); animal2.eat(); // animal2.meow(); // Không thể gọi phương thức meow() } }
Kết quả thực thi chương trình trên:
eating... meowing... eating... eating...
Với nội dung hàm main như trên, tôi đã thực hiện upcasting khi gán đối tượng cat thuộc lớp Cat cho đối tượng animal1 và animal2 thuộc lớp Animal.
Đối với upcasting, chúng ta hoàn toàn có thể sử dụng chuyển kiểu tường mình hoặc không tường minh, cả hai cách đều được chấp nhận.
Một lưu ý nhỏ: Mọi phương thức của lớp Animal hoàn toàn có thể gọi qua 1 đối tượng thuộc lớp Cat do giữa Animal và Cat có quan hệ IS_A. Tuy nhiên, nếu thực hiện override bất kỳ phương thức nào của lớp Animal tại lớp Cat thì trong quá trình runtime hàm được gọi sẽ là hàm của lớp Cat .
Quay trở lại ví dụ phía trên. Nếu trong lớp Cat, thực hiện override hàm eat như sau:
public class Cat extends Animal { @Override public void eat() { System.out.println("Eat meat"); } public void meow() { System.out.println("meowing..."); } }
Kết quả thực thi lại chương trình trên như sau:
Eat meat meowing... Eat meat Eat meat
Downcasting
Khác với upcasting, Downcasting là dạng chuyển kiểu chuyển 1 đối tượng là một thể hiện của lớp cha xuống thành đối tượng là thể hiện của lớp con trong quan hệ kế thừa.
Thông thường, khi thực hiện dòng mã nguồn:
Animal cat = new Cat();
Ta hoàn toàn có thể gọi những phương thức đã được override của lớp Animal tại lớp Cat qua đối tượng animal. Tuy nhiên, vấn đề phát sinh khi ta muốn gọi mọi phương thức của lớp Cat thông qua việc ép kiểu đối tượng thuộc lớp Animal. Khi đó, ta sử dụng downcasting .
Ví dụ:
public class Downcating { public static void main(String[] args) { Animal animal = new Cat(); Cat cat = (Cat) animal; // downcasting cat.meow(); } }
Ta thấy, meow() là phương thức chỉ có ở lớp Cat. Tuy nhiên, thông qua downcasting ta hoàn toàn có thể gọi ra phương thức đó thông qua đối tượng cat mà không cần new Cat() bằng việc downcasting đối tượng animal có kiểu Animal mà không xảy ra vấn đề trong quá trình biên dịch (compile) và thực thi (runtime).
Lưu ý: khi thực hiện downcasting có thể sẽ gặp lỗi ClassCastException nếu không thể thực hiện downcassting được. Để an toàn chúng ta nên kiểm tra một đối tượng có phải là thể hiện của một kiểu dữ liệu cụ thể không trước khi thực hiện downcasting. Xem thêm hướng dẫn ở bài viết Toán tử instanceof trong java.
Tài liệu tham khảo: