显式从超类转换为子类

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 。 为什么编译器不能检测到这个错误?

通过使用一个演员,你基本上告诉编译器“相信我,我是一个专业人士,我知道我在做什么,我知道虽然你不能保证,但我告诉你,这个animalvariables绝对会成为一只狗“。

由于动物实际上不是一只狗(它是一种动物,所以你可以做Animal animal = new Dog();它会是一只狗),VM在运行时会抛出一个exception,因为你违反了这个信任编译器一切都会好起来的,而不是!)

编译器比只是盲目地接受所有东西要聪明一点,如果你尝试在不同的inheritance层次结构中投掷对象(例如将Dog转换为String),那么编译器会把它扔回给你,因为它知道永远不可能工作。

因为你基本上只是停止编译器的抱怨,所以每次ClassCastException ,检查你不会导致一个ClassCastException在if语句中使用instanceof (或类似的东西)。

因为从理论上说, Animal animal 可以是一只狗:

 Animal animal = new Dog(); 

一般来说,向下转换不是一个好主意。 你应该避免它。 如果你使用它,你最好包括一个支票:

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

为了避免这种ClassCastException,如果你有:

 class A class B extends A 

你可以在B中定义一个构造函数,这个构造函数需要A的对象。这样我们就可以执行“cast”了,例如:

 public B(A a) { super(a.arg1, a.arg2); //arg1 and arg2 must be, at least, protected in class A // If B class has more attributes, then you would initilize them here } 

Dog d = (Dog)Animal; //Compiles but fails at runtime

在这里,你正在对编译器说:“相信我,我知道d实际上指的是一个Dog对象”,但事实并非如此。 记住编译器被迫信任我们,当我们做一个downcast

编译器只知道声明的引用types。 运行时的JVM知道对象究竟是什么。

所以当运行时的JVM发现Dog d实际上是指Animal而不是Dog对象的时候。 嘿…你骗了编译器,并抛出一个大胖的ClassCastException

所以,如果你是downcasting你应该使用instanceoftesting,以避免搞砸。

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

现在我们想到了一个问题。 为什么地狱编译器最终会抛出一个java.lang.ClassCastException

答案是所有编译器都可以做的是validation这两种types是在同一个inheritance树中,所以根据在downcast之前可能出现的任何代码,可能是animaldogtypes的。

编译器必须允许可能在运行时工作的东西。

考虑下面的代码snipet:

 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; } 

但是,如果编译器确定该转换不可行,则编译将失败。 IE如果您尝试在不同的inheritance层次结构中投射对象

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

上述两个upcast都能正常工作,没有任何exception情况,因为一只狗可以做一只动物。 但这不是真的,反之亦然。

该代码生成一个编译错误,因为您的实例types是一个动物:

 Animal animal=new Animal(); 

Java中不允许向下转换,原因有几个。 详情请看这里 。

如上所述,这是不可能的。 如果要使用子类的方法,请评估向超类添加方法的可能性(可能为空),并由于多态性而从子类调用,以获取所需的行为(子类)。 所以当你调用d.method()时,调用会成功执行,但是如果对象不是狗,那么就不会有问题