What is this field-by-field copy done by Object.clone()?
Asked Answered
C

4

13

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.

Codee answered 23/5, 2010 at 0:58 Comment(0)
L
6

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.

Lilienthal answered 23/5, 2010 at 4:22 Comment(4)
Why would you not use Java's cloning and write your own method? Any specific reasons?Melano
Read Effective Java. There are a lot of them.Codee
@Melano Since clone() does not create deep copies, I had to implement the clone method's body myself and also bear the burden of Cloneable, and CloneNotSupportedException. Beyond this there are also some other issues why I chose to create my own method. They are explained very well in "Effective Java"Lilienthal
The primitives are done for us? Or do we need to explicitly copy them too?Norm
Z
4

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.

Zoilazoilla answered 23/5, 2010 at 1:1 Comment(2)
Correct, though if the clone method is not implemented as super.clone() it might not implement to the contract.Cockade
Ah yes, this is certainly true. I notice that in the example that he extends Cloneable, which seems incorrect -- you would implement it and then override the Cloneable method (maybe extending Cloneable is how it worked in Java 1?). I suppose that implementing this says that "hey, I've got this special cloneable nature, I clone properly and do a manual deep-copy in my clone method". However, unless you override, clone() from object, as you say, performs a shallow copy.Zoilazoilla
S
4
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;
Straighten answered 23/5, 2010 at 1:38 Comment(0)
A
1

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).

Adamis answered 23/5, 2010 at 6:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.