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

标签 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");
 }
}

鉴于上面的继承,可以理解 Animal 的引用可以引用 Dog 的对象

Animal animal=new Dog();

由于 Dog 对象可以执行 Animal 可以执行的所有操作,就像在上述情况中一样,Dog 也有 sayBye 和 findAnimal 方法。

但是为什么允许将 Animal 对象向下转换为 Dog 对象,这没有任何用处并且在运行时会失败。

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

Dog dog=(Dog)animal;

上面的语句看起来合乎逻辑,因为动物引用指向 Dog 对象。

最佳答案

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

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

void sound(Animal animal) {
    if (animal instanceof Dog) {
        Dog dog = (Dog)animal();
        dog.bark();
    }
    if (animal instanceof Cat) {
        Cat cat = (Cat)animal();
        cat.meow();
    }
}

why it is allowed to compile Dog dog=(Dog) new Animal()

因为编译器设计者决定在编译时不检测这个错误。他们验证了被转换为 Dog 的表达式的类型是 Dog 的父类(super class),并允许表达式编译。他们可以更进一步,检查表达式是否始终会导致异常,但这需要额外的努力,对使用该语言的用户体验的改进微乎其微。

关于java - 为什么在java中允许向下转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30659789/

相关文章:

java - RestEasy - ResteasyServletInitializer 失败

java - 如何使用java byte[]准确发送如此复杂的十六进制、二进制协议(protocol)数据?

c++ - new with inheritance 的不当使用?

scala - 用子类参数覆盖子类方法?

java - Jersey +Grizzly - @ApplicationPath 被忽略

java - 如何在 SPRING 中捕获 Hibernate SQL 异常

java - 该方法和构造函数似乎作用于两个不同的传入/存储变量

python - 在 python 2.7 中扩展类,使用 super()

java继承: distinguish between types of inherited classes

c++ - 访问继承函数