Java Object.clone()所做的逐字段复制是什么?

Java Object.clone()所做的逐字段复制是什么?,java,clone,cloneable,Java,Clone,Cloneable,在有效的Java中,作者声明: 如果类实现了Cloneable, 对象的clone方法返回一个 对象的逐字段副本; 否则它会抛出 CloneNotSupportedException 我想知道的是他对一场一场拷贝的意思。这是否意味着如果类的内存中有X字节,它将只复制该内存块?如果是,那么我是否可以假定原始类的所有值类型都将复制到新对象 class Point implements Cloneable{ private int x; private int y; @Ove

在有效的Java中,作者声明:

如果类实现了Cloneable, 对象的clone方法返回一个 对象的逐字段副本; 否则它会抛出 CloneNotSupportedException

我想知道的是他对一场一场拷贝的意思。这是否意味着如果类的内存中有X字节,它将只复制该内存块?如果是,那么我是否可以假定原始类的所有值类型都将复制到新对象

class Point implements Cloneable{
    private int x;
    private int y;

    @Override
    public Point clone() {
        return (Point)super.clone();
    }
}
如果
Object.clone()
所做的是
Point
类的逐字段复制,我想说我不需要显式复制字段
x
y
,因为上面显示的代码足以复制
Point
类。也就是说,以下代码位是冗余的:

@Override
public Point clone() {
    Point newObj = (Point)super.clone();
    newObj.x = this.x; //redundant
    newObj.y = this.y; //redundant
}
我说得对吗

我知道克隆对象的引用将自动指向原始对象的引用所指向的位置,我只是不确定值类型会发生什么。如果有人能清楚地说明
Object.clone()
的算法规范是什么(用简单的语言),那就太好了。

这意味着一个浅拷贝--字段被拷贝,但是如果你有引用,这些指向的东西就不会被拷贝--你将有两个引用到同一个对象,一个在旧对象中,一个在新对象中,克隆对象。但是,对于具有基元类型的字段,字段本身就是数据本身,因此它们会被复制

newObj.x = this.x; //redundant
newObj.y = this.y; //redundant
没错-这些是多余的,因为它们已经被对象的clone()方法复制了

将其视为数据副本是正确的。将复制基元类型,并复制引用,以便它们指向同一对象。比如说,

class A implements Cloneable {
  Object someObject;
}

A a = new A();
a.someObject = new Object();

A cloneA = (A)a.clone();
assert a.someObject==cloneA.someObject;

是的,逐字段复制确实意味着当它创建新的(克隆的)对象时,JVM将把每个字段的值从原始对象复制到克隆的对象中。不幸的是,这并不意味着你有一个肤浅的副本。如果需要深度复制,可以重写克隆方法

class Line implements Cloneable {

    private Point start;
    private Point end;

    public Line() {
        //Careful: This will not happen for the cloned object
        SomeGlobalRegistry.register(this);
    }

    @Override
    public Line clone() {
        //calling super.clone is going to create a shallow copy.
        //If we want a deep copy, we must clone or instantiate
        //the fields ourselves
        Line line = (Line)super.clone();
        //assuming Point is cloneable. Otherwise we will
        //have to instantiate and populate it's fields manually
        line.start = this.start.clone();
        line.end = this.end.clone;
        return line;
    }
}
关于克隆还有一件更重要的事情,即永远不会调用克隆对象的构造函数(只复制字段)。因此,如果构造函数初始化外部对象,或者向某个注册表注册该对象,那么克隆对象就不会发生这种情况


我个人不喜欢使用Java的克隆。相反,我通常创建自己的“复制”方法。

默认克隆执行值的浅层复制。对于基本值,这就足够了,不需要额外的工作


对于对象,浅复制意味着仅复制参照。因此,在这些情况下,通常需要深度拷贝。当引用指向一个不可变的对象时,这是一个例外。不可变对象不能更改其外观状态,因此可以安全地复制其引用。例如,这适用于字符串、整数、浮点、枚举(如果不是由于错误而变为可变)。

正确,但如果
clone
方法未实现为
super.clone()
,它可能不会实现到协定中。啊,是的,这当然是正确的。我注意到,在这个例子中,他扩展了Cloneable,这似乎是不正确的——您将实现它,然后重写Cloneable方法(也许扩展Cloneable是Java 1中的工作方式?)。我想实现这一点意味着“嘿,我有这种特殊的可克隆性,我正确地克隆,并在我的克隆方法中进行手动深度复制”。然而,除非重写,否则,正如您所说,clone()from object将执行浅层复制?有什么具体原因吗?请阅读有效的Java。它们有很多。@zengr因为clone()不能创建深度拷贝,所以我不得不自己实现clone方法的主体,同时还要承担Cloneable和CloneNotSupportedException的负担。除此之外,我选择创建自己的方法还有一些其他问题。它们在“有效的Java”中得到了很好的解释,原语是为我们做的吗?还是我们也需要明确地复制它们?