虽然一个答案被接受,但我认为它并不能完全回答问题的第一部分(为什么子类中的下放总是有效的)。虽然我无法真正解释它,但我认为我可以澄清海报的一些困惑,这与我的一样。我们有以下课程
class A implements Cloneable
{
@Override
protected A clone() throws CloneNotSupportedException
{
Object clone = super.clone();
System.out.println("Class A: " + clone.getClass());
return (A) clone;
}
}
class B extends A
{
@Override
protected B clone() throws CloneNotSupportedException
{
A clone = super.clone();
System.out.println("Class B: " + clone.getClass());
return (B) clone;
}
}
class C extends B
{
@Override
protected C clone() throws CloneNotSupportedException
{
B clone = super.clone();
System.out.println("Class C: " + clone.getClass());
return (C) clone;
}
}
static main(char[] argv)
{
C c = new C();
C cloned_c = c.clone();
}
这样做的结果是
Class A: C
Class B: C
Class C: C
打印在命令行上。因此,事实上,某种方法可以向下查看调用堆栈,并查看在链的开头调用哪种类型的对象,然后,如果调用气泡向上,以便实际调用,则创建该类型的对象。因此,这在课堂上已经发生过,这很奇怪,但它解释了为什么向下的向下转换不会导致.我已经检查了OpenJDK,似乎这是由一些在本机代码中实现的Java黑魔法实现的。clone()
Object
clone()
Object#clone()
C
ClassCastException