Xây dựng câu trả lời được đưa ra bởi Michael Berry.
Dog d = (Dog)Animal; //Compiles but fails at runtime
Ở đây bạn đang nói với trình biên dịch "Hãy tin tôi. Tôi biết d
là thực sự đang đề cập đến một Dog
đối tượng" mặc dù không phải vậy.
Hãy nhớ rằng trình biên dịch buộc phải tin tưởng chúng tôi khi chúng tôi thực hiện một chương trình truyền hình .
Trình biên dịch chỉ biết về kiểu tham chiếu khai báo. JVM trong thời gian chạy biết đối tượng thực sự là gì.
Vì vậy, khi JVM tại thời gian chạy chỉ ra rằng Dog d
thực sự đang đề cập đến một Animal
và không phải là một Dog
đối tượng mà nó nói. Này ... bạn đã nói dối trình biên dịch và ném một lượng lớn chất béo ClassCastException
.
Vì vậy, nếu bạn đang downcasting, bạn nên sử dụng instanceof
thử nghiệm để tránh làm hỏng.
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
}
Bây giờ một câu hỏi đến với tâm trí của chúng tôi. Tại sao trình biên dịch địa ngục lại cho phép downcast khi cuối cùng nó sẽ ném một java.lang.ClassCastException
?
Câu trả lời là tất cả các trình biên dịch có thể làm là xác minh rằng hai loại nằm trong cùng một cây thừa kế, do đó tùy thuộc vào bất kỳ mã nào có thể xuất hiện trước khi phát sóng, có thể đó animal
là loại dog
.
Trình biên dịch phải cho phép những thứ có thể hoạt động trong thời gian chạy.
Hãy xem xét đoạn mã sau:
public static void main(String[] args)
{
Dog d = getMeAnAnimal();// ERROR: Type mismatch: cannot convert Animal to Dog
Dog d = (Dog)getMeAnAnimal(); // Downcast works fine. No ClassCastException :)
d.eat();
}
private static Animal getMeAnAnimal()
{
Animal animal = new Dog();
return animal;
}
Tuy nhiên, nếu trình biên dịch chắc chắn rằng diễn viên sẽ không thể hoạt động, quá trình biên dịch sẽ thất bại. IE Nếu bạn cố gắng truyền các đối tượng theo các phân cấp thừa kế khác nhau
String s = (String)d; // ERROR : cannot cast for Dog to String
Không giống như downcasting, upcasting hoạt động hoàn toàn bởi vì khi bạn upcast bạn hoàn toàn hạn chế số lượng phương thức bạn có thể gọi, ngược lại với downcasting, ngụ ý rằng sau này, bạn có thể muốn gọi một phương thức cụ thể hơn.
Dog d = new Dog();
Animal animal1 = d; // Works fine with no explicit cast
Animal animal2 = (Animal) d; // Works fine with n explicit cast
Cả hai phần u ám ở trên sẽ hoạt động tốt mà không có ngoại lệ nào bởi vì Chó IS-A Animal, anithing Animal có thể làm, một con chó có thể làm. Nhưng đó không phải là vica-Versa.