Dog d = (Dog)Animal; //Compiles but fails at runtime
在这里,你对编译器说:“相信我。我知道d
真的指的是Dog
对象”,但事实并非如此。 记得编译器是被迫当我们做一个沮丧的信任我们。
编译器只知道声明的引用类型,JVM在运行时知道对象究竟是什么。
因此,当在运行时的JVM出这个Dog d
实际上是指一个Animal
而不是Dog
对象,它说。 嘿......你对编译器撒谎了,并且抛出了一个大胖子ClassCastException
。
所以,如果你是向下倾斜,你应该使用instanceof
测试,以避免搞砸。
现在,一个问题涉及到我们的心灵。为什么地狱编译器在最终抛出一个java.lang.ClassCastException
时允许downcast?
答案是,所有的编译器可以做的是验证两种类型在同一个继承树,所以这取决于什么代码可能已经来过了就垂头丧气 ,它可能是animal
是dog
类型。
编译器必须允许可能在运行时工作的东西。
考虑下面的一小段代码片段:
public static void main(String[] args)
{
Dog d = getMeAnAnimal();// ERROR: Type mismatch: cannot convert Animal to Dog
Dog d = (Dog)getMeAnAnimal(); // Downcast works fine. No ClassCastException :)
d.eat();
}
private static Animal getMeAnAnimal()
{
Animal animal = new Dog();
return animal;
}
但是,如果编译器是确保投将无法工作,编译将失败。 I.E.如果试图投在不同的继承对象层次结构
String s = (String)d; // ERROR : cannot cast for Dog to String
不像向下转换,上溯造型作品含蓄,因为当你上溯造型你都隐含限制方法的数量,您可以调用, 因为对面向下转型,这意味着稍后您可能需要调用更具体的方法。
Dog d = new Dog(); Animal animal1 = d; // Works fine with no explicit cast Animal animal2 = (Animal) d; // Works fine with n explicit cast
上述两个向上转型将正常工作,没有任何异常,因为狗是-A的动物,anithing的动物可以做到,一只狗能做到。但这不是真的,反之亦然。
您正在告诉编译器不检测错误。 – Mauricio 2011-02-01 13:14:02