我有一个关于在一个快速的问题clone()
在Java方法,使用super.clone()
在遗产继承方面的-在我所说的clone()
在父类的方法了从按钮的所有道路。
该clone()
方法应该返回此对象的副本,但是如果我有三个类继承heirachy并调用super.clone()
三次,为什么不中继承heirachy最高级别仅差类对象,获取类的副本回来了?
假设我们有三个类:A,B和C,其中A - >乙 - > C(=继承 - >)
然后调用super.clone()
在C类,调用clone()
在B中调用super.clone()
,调用clone()
在A中调用super.clone()
'这个时候Object.clone()被调用'。 为什么不是副本this
对象相对于A类即会从返回Object.clone()
这听起来逻辑性。
这听起来好像有在这里工作至少存在两个问题:
这听起来像你感到困惑的clone()通常是如何得到实施。
这听起来像你认为克隆是一个好主意(与使用拷贝构造函数,工厂或同等学历)。
下面是一个实施方案的实例的克隆的方法:
@Override
public Object clone() throws CloneNotSupportedException {
//get initial bit-by-bit copy, which handles all immutable fields
Fruit result = (Fruit)super.clone();
//mutable fields need to be made independent of this object, for reasons
//similar to those for defensive copies - to prevent unwanted access to
//this object's internal state
result.fBestBeforeDate = new Date( this.fBestBeforeDate.getTime() );
return result;
}
需要注意的是结果super.clone()
立即转换为一个Fruit
。 其允许继承方法然后修改果实特异性构件数据( fBestBeforeDate
在这种情况下)。
因此,呼叫一个孩子clone()
方法,而它会调用父母的克隆,也增加了自己的具体修改到新抄造。 什么出来,在这种情况下,将是一个Fruit
,而不是一个Object
。
现在,更重要的是, 克隆是一个坏主意 。 拷贝构造函数和工厂提供更加直观和易于维护的替代品。 试着读标题对Java的实践联系起来,我连接到例如:汇总的一些问题。 乔希布洛赫也有更长的讨论 :克隆应绝对避免。 这是为什么他认为克隆是一个问题的一个很好的总结段落:
对象的克隆方法是非常棘手的。 它是基于现场的副本,这是“额外的语言。” 它没有调用构造函数创建一个对象。 有没有保证,它保留通过构造确定的不变量。 已经有大量的漏洞多年来,无论是在和Sun之外,从事实,如果你只需要调用super.clone反复链向上,直到你已经克隆了一个对象,你有对象的浅拷贝而产生。 克隆通常与共享对象被克隆的状态。 如果这种状态是可变的,你没有两个独立的对象。 如果修改了一个,另一个也会改变。 突然之间,你得到随机的行为。
虽然一个答案已被接受,我不认为它完全回答了这个问题(为什么向下转换在子类中始终工作)的第一部分。 虽然我真的不能解释它,我想我可以清理一些海报的混乱这是我的一样。 我们有以下类
class A implements Cloneable
{
@Override
protected A clone() throws CloneNotSupportedException // could be public
{
Object clone = super.clone();
System.out.println("Class A: " + clone.getClass()); // will print 'C'
return (A) clone;
}
}
class B extends A
{
@Override
protected B clone() throws CloneNotSupportedException
{
A clone = super.clone();
System.out.println("Class B: " + clone.getClass()); // will print 'C'
return (B) clone;
}
}
class C extends B
{
@Override
protected C clone() throws CloneNotSupportedException
{
B clone = super.clone();
System.out.println("Class C: " + clone.getClass()); // will print 'C'
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
被印刷在命令行上。 所以,事实上,在clone()
方法Object
在某种程度上可以俯视调用栈,看看对象的哪些类型在链援引开始 clone()
那么,所提供的电话冒泡,使Object#clone()
实际上是所谓的,则创建该类型的一个对象。 所以,这种情况已经在课堂上C
,这是奇怪,但它解释了为什么向下转换不结果ClassCastException
。 我受够了OpenJDK的检查,看来这涉及通过在本机代码中实现一些Java的黑魔法。
它是一种特殊的原生方法。 这样做是为了使克隆容易。 否则,你就必须复制你的祖先类的整个代码。
如果在任何的clone()在B中回报C A收益和用C回报的clone()无论克隆(),然后克隆()乙回报的clone()将返回无论克隆()在A复原。
这个类有关于这个类的信息,以及它与其他类相关联。 所以,从概念上讲这个类的对象有关联的类的信息,以及。 这个对象是没有关联的对象/父完全的对象class.all直接和间接场这一类需要复制使它成为一个值得新的当前对象的克隆。 我们不能访问的参考其中仅表示子部分仅部分。