给出以下代码,我有一个问题:
class A{}
class B extends A {}
class C extends B{}
public class Test {
public static void main(String[] args) {
A a = new A();
A a1=new A();
B b = new B();
// a=b;// ok
// b=(B)a;// ClassCastException
// a=(A)a1; // ok
// a=a1; // ok
a=(B)a1; // compiles ok, ClassCastException
}
}
我的问题是以粗体显示。我的理解是,对于要编译的代码,只需要满足这些类在同一层次结构中,因此它可以工作(在树上隐式转换,在树下需要显式转换)。 每当我遇到ClassCastException时,都是因为引用指向了树上的一个对象,例如指向类型为A的对象的类型B的引用。
有问题的行似乎是指向类型A的对象的类型A的引用。(B)的转换显然是导致ClassCastException的原因。有人可以解释一下它的作用是什么吗?
注意:如果a1指向类型B的对象,那么它可以工作(只是测试它)。因此,对于编译器而言,向下转换是合法的,如果引用指向正确类型的对象,则可以使其无异常地执行。
通过将A ref a1转换为B并将其指定给a,似乎A ref a不再期望引用A类型的对象而是B?
谢谢, 肖恩。
PS我知道这有点不寻常,为Java认证做准备。通常我们向下转到左侧的类型,例如B =(B)一个; (我可以看到为什么会产生ClassCastException)。答案 0 :(得分:4)
所有B都是A,通过继承。但并非所有的A都是B的。这个特定的实例不是,因此是运行时异常。
答案 1 :(得分:2)
您正在尝试将超类引用变量强制转换为子类类型。你不能做这个。认为实际上,超类对象不能包含子类的独立方法(超类'方法除外)。
在运行时,您可以在子类中调用一个方法,该方法当然不在超类对象中。
class A{
public void foo(){}
}
class B extends A {
public void bar(){}
}
现在,
A a=new A();
B b=(B)a;
b.bar();
当您像这样调用编译器时,只会检查bar()
中是否存在方法class B
。而已。它并不关心“对象”中的内容,因为它是在运行时创建的。
但是在运行时,如前所述,对象bar()
中没有a
方法。 b
只是指向对象 a 的引用,但a
仅包含foo()
而不是bar()
答案 2 :(得分:1)
垂头丧气是非法的。 A不是B,因此你不能把它变成一个。你可以把B变为A,但不能反过来。
答案 3 :(得分:1)
在您的代码示例中,变量a
是对A类型对象的引用。
B级扩展了B级,
但是A类和B类之间的关系只能描述如下:
这是合法的:a = (A)b;
因为B类是A类。
考虑它的一种方法是B类是A类的超集。
如果A是包含(1,2)的集合而B是包含(1,2,3)的集合,则B是A的超集(在Java术语中:B可以转换为A)但是A不是B的超集(A不能转为B)。
从不同的角度来看:
苏格拉底(B级)是男人(A级)。
这是一个无效的小主张:所有人都是苏格拉底。
答案 4 :(得分:1)
请记住合法演员表是由“IS-A”测试决定的,为什么你可以编译你的代码?,因为ClassCastException
是一个未经检查的例外,因为从RuntimeException
延伸
ClassCastException --- IS-A - > RuntimeException(可能合法演员的另一个例子)。
答案 5 :(得分:1)
要在Java中向下转换并避免运行时异常,请使用以下代码。
if (animal instanceof Dog) {
Dog dogObject = (Dog) animal;
}
Animal
是父类,Dog
是子类。