public class Animal {
public void eat() {}
}
public class Dog extends Animal {
public void eat() {}
public void main(String[] args) {
Animal animal = new Animal();
Dog dog = (Dog) animal;
}
}
Присвоение Dog dog = (Dog) animal;
не генерирует ошибку компиляции, но во время выполнения оно генерирует ClassCastException
. Почему компилятор не может обнаружить эту ошибку?
java
casting
classcastexception
Saravanan
источник
источник
Ответы:
Используя приведение, вы по существу говорите компилятору: «Поверьте мне. Я профессионал, я знаю, что делаю, и я знаю, что, хотя вы не можете этого гарантировать, я говорю вам, что эта
animal
переменная определенно будет собакой. "Поскольку животное на самом деле не собака (это животное, которое вы могли бы сделать,
Animal animal = new Dog();
и это была бы собака), виртуальная машина выдает исключение во время выполнения, потому что вы нарушили это доверие (вы сказали компилятору, что все будет хорошо, и это не!)Компилятор немного умнее, чем просто вслепую принимать все, если вы попытаетесь привести объекты в различные иерархии наследования (например, приведите Dog к String), то компилятор отбросит его назад вам, потому что знает, что это никогда не сработает.
Поскольку вы, по сути, просто не позволяете компилятору жаловаться, каждый раз, когда вы приводите, важно проверять, не вызовете ли вы
ClassCastException
, используяinstanceof
оператор if (или что-то в этом роде).источник
Dog
действительно, простирается отAnimal
!Потому что теоретически
Animal animal
может быть собакаВообще, уныние не очень хорошая идея. Вам следует избегать этого. Если вы используете его, вам лучше включить проверку:
источник
Чтобы избежать такого рода ClassCastException, если у вас есть:
Вы можете определить конструктор в B, который принимает объект A. Таким образом, мы можем выполнить «приведение», например:
источник
Разработка ответа, который дал Майкл Берри.
Dog d = (Dog)Animal; //Compiles but fails at runtime
Здесь вы говорите компилятору «Поверь мне. Я знаю, что
d
это действительно относится кDog
объекту», хотя это не так. Помните, что компилятор вынужден доверять нам, когда мы делаем уныние .Поэтому, когда JVM во время выполнения выясняет, что
Dog d
фактически ссылается на объект,Animal
а не наDog
объект, он говорит. Эй ... ты солгал компилятору и бросил большой жирClassCastException
.Так что, если вы подавлены, вы должны использовать
instanceof
тест, чтобы не облажаться.if (animal instanceof Dog) { Dog dog = (Dog) animal; }
Теперь возникает вопрос. Почему, черт возьми, компилятор допускает уныние, когда в конечном итоге он собирается бросить
java.lang.ClassCastException
?Ответ заключается в том, что все, что может сделать компилятор, - это убедиться, что оба типа находятся в одном и том же дереве наследования, поэтому в зависимости от того, какой код мог появиться перед понижением, возможно, он
animal
имеет типdog
.Рассмотрим следующий фрагмент кода:
Однако, если компилятор уверен, что приведение не будет работать, компиляция не удастся. IE если вы пытаетесь привести объекты в разные иерархии наследования
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
Оба вышеперечисленных upcast будут отлично работать без каких-либо исключений, потому что Dog IS-A Animal может делать то же самое, что и Animal. Но это не правда, наоборот.
источник
Код генерирует ошибку компиляции, потому что тип вашего экземпляра - Animal:
Даункинг не разрешен в Java по нескольким причинам. Смотрите здесь для деталей.
источник
Как объяснено, это невозможно. Если вы хотите использовать метод подкласса, оцените возможность добавления метода в суперкласс (может быть пустым) и вызов из подклассов, чтобы получить желаемое поведение (подкласс) благодаря полиморфизму. Поэтому, когда вы вызываете d.method (), вызов будет успешным без приведения, но в случае, если объект будет не собакой, проблем не будет
источник
Чтобы разработать ответ @Caumons:
Теперь взгляните на это решение.
Сейчас мы тестируем приложение:
И вот результат:
Теперь вы можете легко добавлять новые поля в класс отца, не беспокоясь о том, что ваши дочерние коды могут быть взломаны;
источник