Shu*_*eng 13 java inheritance clone object instance
我有一个关于clone()Java中的方法的快速问题,用于super.clone()继承 - 我clone()从父按钮中一直调用父类中的方法.
该clone()方法应该返回该对象的副本,但是如果我在继承heirachy中有三个类并且调用super.clone()三次,为什么继承heirachy中的最高类(仅在类Object下)得到该类的副本回?
假设我们有三个类:A,B和C,其中A - > B - > C(inherit = - >)
然后super.clone()在C类中调用,调用clone()B调用super.clone(),clone()在A中调用,调用super.clone()'this this Object.clone()被调用'.为什么它不是this从A类返回的对象的副本Object.clone()?这听起来很合乎逻辑.
Bob*_*oss 12
听起来这里至少有两个问题在起作用:
听起来你对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;
}
Run Code Online (Sandbox Code Playgroud)
注意,结果super.clone()立即转换为a Fruit.这允许继承方法然后修改Fruit特定的成员数据(fBestBeforeDate在本例中).
因此,调用子clone()方法虽然它将调用父类的克隆,但也会对新制作的副本添加自己的特定修改.在这种情况下,出来的将是一个Fruit,而不是一个Object.
现在,更重要的是,克隆是一个坏主意.复制构造函数和工厂提供了更直观,易于维护的替代方案.尝试阅读我附加到示例的Java Practices链接上的标题:它总结了一些问题.Josh Bloch还有一个更长的讨论:绝对应该避免克隆.以下是关于他认为克隆是一个问题的原因的优秀摘要段落:
Object的clone方法非常棘手.它基于现场副本,而且是"超语言".它创建一个对象而不调用构造函数.无法保证它保留构造函数建立的不变量.多年来,在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();
}
Run Code Online (Sandbox Code Playgroud)
这样做的结果是
Class A: C
Class B: C
Class C: C
打印在命令行上。因此,事实上,该clone()方法Object可以以某种方式查看调用堆栈并查看调用链开头的clone()哪种类型的对象,然后,只要调用冒泡Object#clone(),以便实际调用该类型的对象被建造。所以这种情况已经在 class 中发生了C,这很奇怪,但它解释了为什么向下转型不会导致ClassCastException. 我检查过 OpenJDK,看来这是由一些在本机代码中实现的 Java 黑魔法造成的。
| 归档时间: |
|
| 查看次数: |
15843 次 |
| 最近记录: |