从超类到子类的显式转换

2022-08-31 06:49:59
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


答案 1

通过使用强制转换,你实际上是在告诉编译器“相信我。我是一名专业人士,我知道我在做什么,我知道虽然你不能保证,但我告诉你,这个变量肯定会成为一只狗。animal

由于动物实际上不是狗(它是动物,你可以这样做,它将是一只狗),VM在运行时会引发异常,因为你违反了这种信任(你告诉编译器一切都会好起来的,但事实并非如此!Animal animal = new Dog();

编译器比盲目地接受所有内容要聪明一些,如果你尝试将对象转换为不同的继承层次结构(例如,将Dog转换为字符串),那么编译器会把它扔回给你,因为它知道这永远不可能工作。

因为你基本上只是在阻止编译器抱怨,所以每次你强制转换时,重要的是要检查你不会通过在if语句中使用(或类似的东西)来导致a。ClassCastExceptioninstanceof


答案 2

因为理论上可以成为一只狗:Animal animal

Animal animal = new Dog();

通常,下倾不是一个好主意。你应该避免它。如果您使用它,最好包括一个检查:

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

推荐