为什么在java中允许向下转换?

Pan*_*kaj 1 java inheritance

class Animal{
  public void findAnimal(){
    System.out.println("Animal class");
  }
  public void sayBye(){
    System.out.println("Good bye");
  }
}

class Dog extends Animal{
 public void findAnimal(){
  System.out.println("Dog class");
 }
}
Run Code Online (Sandbox Code Playgroud)

鉴于上述继承,可以理解Animal的参考可以指Dog的一个对象

Animal animal=new Dog();
Run Code Online (Sandbox Code Playgroud)

由于Dog对象可以执行动物可以执行的所有操作,如上面的情况,Dog也有sayBye和findAnimal方法.

但是为什么允许将一个Animal对象向下转换为Dog对象,该对象没有用处并且在运行时失败.

Dog dog=(Dog)new Animal(); // fails at runtime but complies.

Dog dog=(Dog)animal;
Run Code Online (Sandbox Code Playgroud)

上面的语句看起来很合理,因为动物引用指向Dog对象.

das*_*ght 5

当您从外部代码获取超类的对象时,例如作为方法的参数,然后您需要调用特定于子类的方法时,允许这种类型的转换.

这不是一个好习惯,但在一些罕见的情况下,你被迫做这样的事情,所以语言允许:

void sound(Animal animal) {
    if (animal instanceof Dog) {
        Dog dog = (Dog)animal();
        dog.bark();
    }
    if (animal instanceof Cat) {
        Cat cat = (Cat)animal();
        cat.meow();
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么允许编译 Dog dog=(Dog) new Animal()

因为编译器设计者决定在编译时不检测此错误.他们验证了要转换Dog为的表达式是超类的类型Dog,并允许表达式进行编译.他们可以更进一步检查表达式是否总是会导致异常,但这需要额外的努力才能在语言的用户体验方面获得很少的改进.