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对象.
当您从外部代码获取超类的对象时,例如作为方法的参数,然后您需要调用特定于子类的方法时,允许这种类型的转换.
这不是一个好习惯,但在一些罕见的情况下,你被迫做这样的事情,所以语言允许:
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,并允许表达式进行编译.他们可以更进一步检查表达式是否总是会导致异常,但这需要额外的努力才能在语言的用户体验方面获得很少的改进.