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

发布于 2024-09-02 12:48:45 字数 906 浏览 5 评论 0原文

在《Effective 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 类,我会说我不需要显式复制字段 xy,因为上面显示的代码足以克隆 Point 类。也就是说,下面的代码是多余的:

@Override
public Point clone() {
    Point newObj = (Point)super.clone();
    newObj.x = this.x; //redundant
    newObj.y = this.y; //redundant
}

我说得对吗?

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

In Effective Java, the author states that:

If a class implements Cloneable,
Object's clone method returns a
field-by-field copy of the object;
otherwise it throws
CloneNotSupportedException.

What I'd like to know is what he means with field-by-field copy. Does it mean that if the class has X bytes in memory, it will just copy that piece of memory? If yes, then can I assume all value types of the original class will be copied to the new object?

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

    @Override
    public Point clone() {
        return (Point)super.clone();
    }
}

If what Object.clone() does is a field by field copy of the Point class, I'd say that I wouldn't need to explicitly copy fields x and y, being that the code shown above will be more than enough to make a clone of the Point class. That is, the following bit of code is redundant:

@Override
public Point clone() {
    Point newObj = (Point)super.clone();
    newObj.x = this.x; //redundant
    newObj.y = this.y; //redundant
}

Am I right?

I know references of the cloned object will point automatically to where the original object's references pointed to, I'm just not sure what happens specifically with value types. If anyone could state clearly what Object.clone()'s algorithm specification is (in easy language) that'd be great.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

吹泡泡o 2024-09-09 12:48:45

是的,逐个字段复制确实意味着当它创建新(克隆)对象时,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的克隆。相反,我通常创建自己的“复制”方法。

Yes, a field by field copy does mean that when it creates the new (cloned) object, the JVM will copy the value of every field from the original object into the cloned object. Unfortunately this does mean that you have a shallow copy. If you desire a deep copy, you can override the clone method.

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;
    }
}

Also one more important thing about the cloning is, the constructor of the cloned object is never invoked (only the fields are copied). So if the constructor initializes an external object, or registers this object with some registry, then that will not happen for the cloned object.

I personally prefer to not use Java's cloning. Instead I usually create my own "duplication" methods.

夜清冷一曲。 2024-09-09 12:48:45

这意味着浅复制 - 字段被复制,但如果你有任何引用,这些指向的内容不会被复制 - 你将有对同一个对象的两个引用,一个在旧对象中,一个在新的克隆对象中目的。但是,对于具有原始类型的字段,该字段就是数据本身,因此无论如何它们都会被复制。

It means a shallow copy -- the fields are copied, but if you have any references, what these point to is not copied -- you will have two references to the same object, one in the old object and one in the new, cloned object. However, for fields that have primitive types, the field is the data itself, so they get copied regardless.

咽泪装欢 2024-09-09 12:48:45
newObj.x = this.x; //redundant
newObj.y = this.y; //redundant

没错 - 这些是多余的,因为它们已经被 Object 的 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;
newObj.x = this.x; //redundant
newObj.y = this.y; //redundant

that's right - these are redundant, since they will have already been copied by Object's clone() method.

Thinking of it as a data copy is correct. Primitive types are copied, and references are also copied so they point to the same object. For example,

class A implements Cloneable {
  Object someObject;
}

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

A cloneA = (A)a.clone();
assert a.someObject==cloneA.someObject;
死开点丶别碍眼 2024-09-09 12:48:45

默认克隆执行值的浅表复制。对于原始值来说,这已经足够了,不需要额外的工作。

对于对象来说,浅拷贝意味着仅复制引用。因此,在这些情况下通常需要深拷贝。例外情况是当引用指向不可变对象时。不可变对象无法更改其表观状态,因此可以安全地复制它们的引用。例如,这适用于字符串、整数、浮点、枚举(如果没有错误地使其可变)。

The default clone performs shallow copy of values. For primitive values, this is enough and no extra work is needed.

For objects, the shallow copy means copying the reference only. Therefore, in these cases a deep copy is usually needed. The exception for this is when the reference points to an immutable object. Immutable objects can't have their apparent state changed, therefore their references can be copied around safely. For example, this applies to String, Integer, Float, enumerations (if not made mutable by mistake).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文