"Xin chào, Amigo! Chủ đề của bài học hôm nay là mở rộng và thu hẹp các chuyển đổi kiểu. Bạn đã học về mở rộng và thu hẹp các kiểu nguyên thủy từ lâu. Ở Cấp độ 10. Hôm nay chúng ta sẽ nói về cách thức hoạt động của các kiểu tham chiếu, tức là thể hiện của các lớp."

Trên thực tế, tất cả đều khá đơn giản. Hãy tưởng tượng chuỗi kế thừa của một lớp: lớp đó, cha của nó, cha của cha, v.v., tất cả đều quay trở lại lớp Đối tượng. Bởi vì một lớp chứa tất cả các phương thức thành viên của lớp mà nó kế thừa , nên một thể hiện của lớp có thể được lưu trong một biến có kiểu là bất kỳ biến cha của nó.

Đây là một ví dụ:

Mã số Sự miêu tả
class Animal
{
public void doAnimalActions();
}class Cat extends Animal
{
public void doCatActions();
}class Tiger extends Cat
{
public void doTigerActions();
}
Ở đây chúng ta có ba khai báo lớp: Animal, Cat và Tiger. Mèo kế thừa Thú. Còn Hổ kế thừa Cát.
public static void main(String[] args)
{
Tiger tiger = new Tiger();
Cat cat = new Tiger();
Animal animal = new Tiger();
Object obj = new Tiger();
}
Một đối tượng Tiger luôn có thể được gán cho một biến có kiểu của một trong các tổ tiên của nó. Đối với lớp Tiger, đây là Cat, Animal và Object.

Bây giờ, hãy xem xét mở rộng và thu hẹp chuyển đổi.

Nếu một thao tác gán khiến chúng ta di chuyển lên chuỗi kế thừa (về phía lớp Đối tượng), thì chúng ta đang xử lý một chuyển đổi mở rộng (còn được gọi là upcasting). Nếu chúng ta di chuyển xuống chuỗi về phía loại đối tượng, thì đó là một chuyển đổi thu hẹp (còn được gọi là downcasting).

Di chuyển lên chuỗi thừa kế được gọi là mở rộng, bởi vì nó dẫn đến một loại tổng quát hơn. Tuy nhiên, khi làm như vậy, chúng ta mất khả năng gọi các phương thức được thêm vào lớp thông qua kế thừa.

Mã số Sự miêu tả
public static void main(String[] args)
{
Object obj = new Tiger();
Animal animal = (Animal) obj;
Cat cat = (Cat) obj;
Tiger tiger = (Tiger) animal;
Tiger tiger2 = (Tiger) cat;
}
Khi thu hẹp loại cần sử dụng toán tử chuyển loại, tức là ta thực hiện chuyển đổi tường minh.

Điều này khiến máy Java kiểm tra xem đối tượng có thực sự kế thừa loại mà chúng ta muốn chuyển đổi nó thành hay không.

Sự đổi mới nhỏ này đã tạo ra sự giảm thiểu nhiều lần về số lượng lỗi truyền kiểu và tăng đáng kể tính ổn định của các chương trình Java.

Mã số Sự miêu tả
public static void main(String[] args)
{
Object obj = new Tiger();
if (obj instanceof Cat)
{
Cat cat = (Cat) obj;
cat.doCatActions();
}}
Tốt hơn nữa, hãy sử dụng  kiểm tra instanceof
public static void main(String[] args)
{
Animal animal = new Tiger();
doAllAction(animal);

Animal animal2 = new Cat();
doAllAction(animal2);

Animal animal3 = new Animal();
doAllAction(animal3);
}

public static void doAllAction(Animal animal)
{
if (animal instanceof Tiger)
{
Tiger tiger = (Tiger) animal;
tiger.doTigerActions();
}

if (animal instanceof Cat)
{
Cat cat = (Cat) animal;
cat.doCatActions();
}

animal.doAnimalActions();
}
Và đây là lý do tại sao. Hãy xem ví dụ bên trái.

Chúng tôi (mã của chúng tôi) không phải lúc nào cũng biết chúng tôi đang làm việc với loại đối tượng nào. Nó có thể là một đối tượng cùng loại với biến (Động vật) hoặc bất kỳ loại hậu duệ nào (Mèo, Hổ).

Hãy xem xét phương thức doAllAction. Nó hoạt động chính xác, bất kể loại đối tượng được truyền vào.

Nói cách khác, nó hoạt động chính xác cho cả ba loại: Động vật, Mèo và Hổ.

public static void main(String[] args)
{
Cat cat = new Tiger();
Animal animal = cat;
Object obj = cat;
}
Ở đây chúng ta có ba thao tác gán. Tất cả chúng đều là ví dụ về việc mở rộng chuyển đổi.

Toán tử truyền kiểu không cần thiết ở đây, vì không cần kiểm tra. Một tham chiếu đối tượng luôn có thể được lưu trữ trong một biến có kiểu là một trong các tổ tiên của nó.

"Ồ, ví dụ thứ hai đến cuối cùng đã làm rõ mọi thứ: tại sao cần kiểm tra và tại sao cần truyền kiểu."

"Tôi hy vọng như vậy. Tôi muốn thu hút sự chú ý của bạn vào thực tế này:"

Không điều nào trong số này làm cho một đối tượng thay đổi theo bất kỳ cách nào! Điều duy nhất thay đổi là số phương thức có sẵn để được gọi trên một biến tham chiếu cụ thể.

Ví dụ: một biến Cat cho phép bạn gọi các phương thức doAnimalActions và doCatActions. Nó không biết gì về phương thức doTigerActions, ngay cả khi nó trỏ đến một đối tượng Tiger.

"Vâng, tôi hiểu rồi. Nó dễ hơn tôi nghĩ."