Разработка ответа, данного Майклом Берри.
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;
}
Однако, если компилятор уверен, что приведение не сработает, компиляция завершится ошибкой. т.е. Если вы пытаетесь привести объекты в разные иерархии наследования
String s = (String)d; // ERROR : cannot cast for Dog to String
В отличие от понижающего приведения, восходящее приведение работает неявно, потому что при восходящем приведении вы неявно ограничиваете количество методов, которые вы можете вызывать, в отличие от понижающего приведения, что подразумевает, что позже вы можете захотеть вызвать более конкретный метод.
Dog d = new Dog();
Animal animal1 = d; // Works fine with no explicit cast
Animal animal2 = (Animal) d; // Works fine with n explicit cast
Оба приведенных выше приведения будут работать нормально без каких-либо исключений, потому что Собака ЕСТЬ-Животное, и все, что может сделать Животное, может сделать и собака. Но это не так наоборот.
person
Zeeshan
schedule
23.06.2014