为什么超类对象不能在Java中隐式转换为子类对象?

时间:2012-03-19 13:15:42

标签: java reference-type

我有以下代码:

class A {
}

class B extends A {
    public void fB(){};
}

根据Java规则:

案例1:

B b = new B();
A a = b;
((B)a).fB();

案例2:

A a = new A();
B b = a;

根据Java规则,案例1 确定,案例2 不正常。为什么案例2 不正常?这条线((B)a).fB();实际上做了什么(我的意思是里面发生了什么)?

4 个答案:

答案 0 :(得分:14)

为什么案例1没问题且案例2不正常:因为DogAnimal,但并非每个Animal都是Dog

class Animal { }
class Dog extends Animal { }
class Cat extends Animal { }

Dog fifi = new Dog();
Cat tommy = new Cat();

// OK because Dogs and Cats are Animals
Animal pet1 = fifi;
Animal pet2 = tommy;

// Not OK because an Animal is not always a Dog
Dog doggy = pet2;

请注意,强制转换对对象没有任何作用;特别是,它不会对对象进行任何类型的转换。 Casting只告诉编译器“我在这里有这个对象,我比你知道的更好;我希望你把它当作X型而不是给我任何错误信息”。

所以在这样的一行:

Dog doggy = pet2;

编译器会抱怨,因为它无法确定pet2实际上是Dog;它只知道它是Animal - 而且并非所有Animal都是Dog。你可以做一个演员来告诉编译器不要抱怨这个:

// Tell the compiler that you want it to treat pet2 as a Dog
Dog doggy = (Dog)pet2;

但是当你运行该程序时,Java仍会检查pet2是否真的是Dog,如果不是,那么你会得到ClassCastException

(你的标题中的问题恰恰与你的意思相反,正如biziclop注意到的那样。)

答案 1 :(得分:2)

好的,想想2个人:医生和工程师。医生可以治疗,工程师可以建立。两人都是人。

现在这是你的例子。

Person p = new Person(); // somebody that does not know to do anything special.
Doctor d = (Doctor)p; // do you think that casting makes person that does not know anything to be a doctor?

你是否想被那些被“演员”作为医生的人对待你更喜欢真正的医生吗?

我相信答案很清楚。 每个医生都是一个人(病例1)但不是每个人都是医生,因为不是每个人都可以治疗。完全相同也与类层次结构相关。子类继承其超类的属性,并可能添加自己的属性。因此,不能将任何超类实例强制转换为子类。

答案 2 :(得分:0)

案例1没问题,因为(B)是您明确告诉编译器的一部分:

  

即使您只知道A是A类型,我告诉您它是B类型

因此对象a被视为类型B

案例2不正常,因为编译器无法安全地将b分配给a。如果你写了

就会被接受
A a = new A();
B b = (B)a;

但它会在运行时抛出异常

答案 3 :(得分:0)

假设情况2也有效,那么您的编译器将“b”视为类“B”的对象。现在你可以说“b.fb()”。但实际上“b”是“A”的对象(记住你将“A”类的对象分配给“b”)。类“A”中没有函数fb()。你的应用程序崩溃了!!