Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Effective Java claims that elements.clone() suffices

Tags:

java

I'm reading on Joshua Bloch's Effective Java, 2nd edition, Item 11: Override clone judiciously.

On page 56, he is trying to explain that when we override clone() for some classes (like collection classes), we must copy the internals of it. He then gives the example of designing a class Stack:

public class Stack {
    private Object[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;
    public Stack() {...}
    public void push(Object e) {...}
    public Object pop() {...}
    private void ensureCapacity() {...} //omitted for simplicity
}

He claims that if we simply use super.clone() to clone a Stack, the resulting Stack instance "will have the correct value in its size field, but its elements field will refer to the same array as the original Stack instance. Modifying the original will destroy the invariants in the clone and vice versa. You will quickly find that your program produces nonsensical results or throws a NullPointerException." Now that seems fair. But he then gives an example of the "correct implementation", which confuses me:

@Override public Stack clone() {
    try {
        Stack result = (Stack) super.clone();
        result.elements = elements.clone();
        return result;
    } catch (CloneNotSupportedException e) {
        throw new AssertionError();
    }
}

Now how is that different from super.clone()? I know, the new Stack.element will be a different reference than the old one and all; but the "internals" of the array are still the same, aren't they? The actual elements of the array result.element still point to the original Object references. That could still result in destroying the invariants of the clone when changing the original, or vice versa, couldn't it? Am I missing anything?

like image 685
justgivememyicecream Avatar asked Jul 25 '18 09:07

justgivememyicecream


People also ask

What is clone and copy in Java?

The object cloning is a way to create exact copy of an object. The clone() method of Object class is used to clone an object. The java. lang. Cloneable interface must be implemented by the class whose object clone we want to create.

What is the return type of clone method?

clone() method returns a Shallow Copy. In shallow copy, if the field value is a primitive type, it copies its value; otherwise, if the field value is a reference to an object, it copies the reference, hence referring to the same object.

Why do we need to override clone method in Java?

Because, for a class to be cloned, you need to implement the Cloneable interface. And then your class uses the clone method of Object class instead. Because, Cloneable interface doesn't exactly have any method for cloning . It would be a better option to use Copy Constructor instead.

Can we override clone method in Java?

From Java 1.5 onwards an overriding method can return subclass of return type declared in original method, which means you can return sub class from clone method. It is known as co-variant method overriding.

What are the side-effects of using clone () method in Java?

clone () method has no side-effects in case of primitives instance variables, as a new object is created during cloning. clone () method if not implemented properly, too has side-effects in case of objects as instance variables, as a cloned object to has a copy of references.

How to clone an object in Java?

1 Every class that implements clone () should call super.clone () to obtain the cloned object reference. 2 The class must also implement java.lang.Cloneable interface whose object clone we want to create otherwise it will throw CloneNotSupportedException when clone method is called on that class’s object. 3 Syntax:

Why do I get an exception when cloning an object?

Those applications which override the clone method can also throw this type of exception to indicate that an object couldn’t or shouldn’t be cloned.

What is the return value of the cloned object function?

Return Value: The function returns the cloned Object which is the shallow copy of this Properties instance. Below programs illustrate the Java.util.Properties.clone () method.


1 Answers

Now how is that different from super.clone()?

Because the arrays are now different. If two Stacks share the same array then, when one adds or removes from the stack, the size field in the other Stack is not updated, leading to discrepancies.

The array's objects are not cloned themselves. This is deliberate as they do not need to be cloned. It is expected that two Stacks - or indeed any two Collections - can contain references to the same objects. You would get the same behaviour with this code:

Foo foo = new Foo()
Stack stackOne = new Stack();
Stack stackTwo = new Stack();
stackOne.push(foo);
stackTwo.push(foo);

It's not inherently a problem, and is usually the desirable behaviour.

like image 109
Michael Avatar answered Oct 29 '22 15:10

Michael