явное приведение от суперкласса к подклассу


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. Почему компилятор не может обнаружить эту ошибку?

6 117

6 ответов:

используя приведение, вы по существу говорите компилятору " доверьтесь мне. Я профессионал, я знаю, что я делаю, и я знаю, что, хотя вы не можете гарантировать это, я говорю вам, что это animal переменная определенно будет собака."

так как животное на самом деле не собака (это животное, вы могли бы сделать Animal animal = new Dog(); и это была бы собака) виртуальная машина выдает исключение во время выполнения, потому что вы нарушили это доверие (вы сказали компилятору, что все будет в порядке, и это нет!)

компилятор немного умнее, чем просто слепо принимать все, если вы попытаетесь привести объекты в разные иерархии наследования (например, бросить собаку в строку), тогда компилятор бросит его обратно на вас, потому что он знает, что это никогда не сработает.

потому что вы по существу просто останавливаете компилятор от жалоб, каждый раз, когда вы бросаете, важно проверить, что вы не вызовете ClassCastException С помощью instanceof в операторе if (или что-то в этом роде.)

потому что теоретически Animal animalможете быть собакой:

Animal animal = new Dog();

как правило, понижение не является хорошей идеей. Вы должны избегать этого. Если вы используете его, вам лучше включить чек:

if (animal instanceof Dog) {
    Dog dog = (Dog) animal;
}

чтобы избежать такого рода ClassCastException, если у вас есть:

class A
class B extends A

вы можете определить конструктор в B, который принимает объект A. Таким образом, мы можем сделать "cast", например:

public B(A a) {
    super(a.arg1, a.arg2); //arg1 and arg2 must be, at least, protected in class A
    // If B class has more attributes, then you would initilize them here
}

Dog d = (Dog)Animal; //Compiles but fails at runtime

здесь вы говорите компилятору " поверьте мне. Я знаю d действительно относится к

код вызовет ошибку компиляции, потому что ваш экземпляр типа - Это животное:

Animal animal=new Animal();

Downcasting не допускается в Java по нескольким причинам. Смотрите здесь для сведения.

Как уже объяснялось, это невозможно. Если вы хотите использовать метод подкласса, оцените возможность добавления метода в суперкласс (может быть пустым) и вызовите из подклассов, получая поведение, которое вы хотите (подкласс) благодаря полиморфизму. Поэтому при вызове d. method () вызов будет успешным без кастинга, но в случае, если объект не будет собакой, не будет проблемы