Розвиток відповіді, даної Майклом Беррі.
Dog d = (Dog)Animal; //Compiles but fails at runtime
Ось ви говорите компілятору "Повір мені. Я знаю d
, що справді йдеться про Dog
об'єкт", хоча це не так.
Пам'ятайте, що компілятор змушений нам довіряти, коли ми робимо спад .
Компілятор знає лише про заявлений тип посилання. JVM під час виконання роботи знає, що є об'єктом насправді.
Отже, коли JVM під час виконання з'ясовує, що Dog d
справді йдеться про об'єкт, який він говорить, Animal
а не Dog
об'єкт. Гей ... ти брешеш компілятору і кидаєш великий жир ClassCastException
.
Тож якщо ви перебуваєте на каналі, вам слід скористатися instanceof
тестом, щоб уникнути викручування.
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
}
Тепер питання нам приходить в голову. Чому чортовий компілятор дозволяє скинути, коли врешті-решт він збирається кинути java.lang.ClassCastException
?
Відповідь полягає в тому, що все, що може зробити компілятор, - це перевірити, чи є два типи в одному дереві спадкування, тож залежно від того, який код міг би бути до занепаду, можливо, він animal
має тип dog
.
Компілятор повинен дозволити речі, які могли б працювати під час виконання.
Розглянемо наступний фрагмент коду:
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;
}
Однак, якщо компілятор впевнений, що передача не змогла б працювати, компіляція не вдасться. IE Якщо ви намагаєтеся викидати об'єкти в різні ієрархії спадкування
String s = (String)d; // ERROR : cannot cast for Dog to String
На відміну від downcasting, оновлення працює неявно, тому що, коли ви поновлюєтеся, ви неявно обмежуєте кількість методів, які ви можете викликати, як протилежне до downcasting, що означає, що пізніше ви можете захотіти використовувати більш конкретний метод.
Dog d = new Dog();
Animal animal1 = d; // Works fine with no explicit cast
Animal animal2 = (Animal) d; // Works fine with n explicit cast
Обидва вищезгадані події будуть справно працювати без будь-якого винятку, тому що собака IS-A тварина, яка може робити аніт тварини, може робити і собака. Але це неправда vica навпаки.