What is the reason for ever needing to clone an object in java?
Asked Answered
M

4

5

I was reading Joshua Bloch's Effective Java. In there he talks about not using the Clonable interface. I'm a bit of a noob so my question is, whats a use-case for when cloning would be required in code? Could someone give a sticky example so I can grasp the concept?

Minhminho answered 14/5, 2014 at 2:34 Comment(5)
Why on hold? I don't know reason for cloning. If an example is there it would help me understand what the heck cloning an object really does..Minhminho
I agree. What it does is produce a bitwise copy of the object, unless its base class or any of its members have clone() methods, in which case it does what they do for those parts. But I've never used clone() in production Java since 1997, or a so-called 'copy contructor' either. Never ever met a genuine requirement for it.We
what do you mean by a bitwise copy of the object?Minhminho
@TazMan If you were to examine the original object and its clone in memory, you would see two distinct regions of memory which look exactly identicalContradistinction
@TazMan I mean that every bit is copied identically. Surely it's self-explanatory? It's meant to be.We
L
6

A clone() interface provides a mechanism to create a "shallow" copy of an object. That is, by default, more memory would be allocated for the copy, and each part of the original would be copied into the copy. In contrast, a simple assignment of an object instance to a variable would result in an additional reference to the same object. While the cloned object is itself a true copy, its contained elements are by default references to the ones referred to from the original. If a true "deep" copy is needed, the clone() method would need to be specialized to create clones of its members as well.

One possible use case for a clone() interface would be for implementing a version history of an object to allow a rollback to an older version of it. This could be used in transactional systems, like databases.

Another use case would be for implementing copy-on-write, and this can be useful when the user of the object is only provided a read-only version of the object.

* Description of clone corrected, with thanks and kudos to newacct.

Lyrist answered 14/5, 2014 at 3:43 Comment(5)
Correct me if I'm wrong but I don't think object assignment is a shallow copy. Thats actually just another pointer pointing to the same object. Where is the clone there??Minhminho
What you call "deep copy" is what people usually call "shallow copy".Epileptoid
Wait, what? From the Java API: "this means copying any mutable objects that comprise the internal 'deep structure' of the object being cloned and replacing the references to these objects with references to the copies." That sounds like a deep copy to me. docs.oracle.com/javase/7/docs/api/java/lang/…Curtsy
@cecilg23: The paragraph after of the same doc: "Thus, this method performs a "shallow copy" of this object, not a "deep copy" operation."Lyrist
Ok, I see what you're saying now, and you're right. But I guess my point is that the point of overriding the base clone() method (which is what the question is about) is to ensure by design that a deep copy is performed. If you simply implement the Cloneable interface, and no more, then a shallow copy is what you get, as that interface does not require that you override the clone() method.Curtsy
C
2

From Wikipedia on the Prototype pattern,

... you would need to clone() an Object when you want to create another Object at runtime that is a true copy of the Object you are cloning. True copy means all the attributes of the newly created Object should be the same as the Object you are cloning. If you could have instantiated the class by using new instead, you would get an Object with all attributes as their initial values. For example, if you are designing a system for performing bank account transactions, then you would want to make a copy of the Object that holds your account information, perform transactions on it, and then replace the original Object with the modified one. In such cases, you would want to use clone() instead of new.

Codicodices answered 14/5, 2014 at 3:40 Comment(0)
C
1

There are very good reasons for cloning an object in Java. Consider the following code:

MyObj first = new MyObj(someOwner, someTag, someInt);
MyObj second = first;

In this case, we are simply copying the reference (memory address) of that object. The variables first and second both refer to the same instance of the MyObj class. What the clone() method is supposed to achieve is what is called a deep copy. This is, of course, implementation dependent: the developer of the clone method needs to ensure that a deep copy is actually what is being achieved. So, the code:

MyObj third = (MyObj) first.clone();

What clone() does in this case is go through all of first's instance members and copy/clone those, and uses those values to create an entirely new MyObj instance. It then returns a reference to the new instance, so third is a copy of first, not just a reference to the same instance.

In response to your question in the comments, it depends on your implementation whether or not clone makes new clones of member variables, or simply copies the reference over. Consider the following implementation of the MyObj example class, supposing there also exist classes Person and NameTag. If you clone a MyObj object, you might want the new clone to refer to the same Owner instance as the original, but make a deep copy of the NameTag (this is just an example using imaginary classes, of course). This would represent a one-to-one relationship between MyObj and NameTag instances, and a one-to-many relationship between Owner and MyObj instances. The following code considers both cases mentioned in your question:

class MyObj implements Cloneable {

    private Person owner;
    private NameTag tag;
    private int size; 

    public MyObj(Person owner, NameTag tag, int size) {
         this.owner = owner;
         this.tag = tag;
         this.size = size;
    }

    public Object clone() {

        MyObj result;

        //call all super clone() methods before doing class specific work
        //this ensures that no matter where you are in the inheritance heirarchy,
        //a deep copy is made at each level.
        try {
            result = (MyObj) super.clone();
        }
        catch (CloneNotSupportedException e) {
            throw new RuntimeException
            ("Super class doesn't implement cloneable");
        }

        //work specific to the MyObj class
        result.owner = owner;     //We want the reference to the Person, not a clone
        result.tag = tag.clone()  //We want a deep copy of the NameTag
        result.size = size;       //ints are primitive, so this is a copy operation    

        return result;
}
Curtsy answered 14/5, 2014 at 3:41 Comment(4)
What if first instance contained other reference variables and lists, would doing first.clone() actually make clones of those too?Minhminho
I updated my answer to address those questions in more detail. Let me know if that makes it more clear!Curtsy
But how is it better than MyObj having a "copy constructor" (a constructor that takes a MyObj), and using that instead?Epileptoid
Neither approach is better than the other, really. It's just that clone is a standard Java paradigm. The copy constructor is a C++ paradigm. Either approach will work fine in either language, but clone has some extra failsafes for inter compatibility (as outlined above) when implemented properly in Java.Curtsy
A
1

One example is defensive copying of parameters (Effective Java Item 39: Make defensive copies when needed)

class X {
  private byte[] a;

  X(byte[] a) {
      this.a = a.clone();
  }
...
Aili answered 14/5, 2014 at 4:5 Comment(2)
what does this allow?Minhminho
It ensures that the new X instance has an independent copy of the passed-in byte array as its instance member as opposed to a reference to the passed object.Curtsy

© 2022 - 2024 — McMap. All rights reserved.