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?

Qix - MONICA WAS MISTREATED
  • 14,451
  • 16
  • 82
  • 145
Horse Voice
  • 8,138
  • 15
  • 69
  • 120
  • 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.. – Horse Voice May 14 '14 at 02:38
  • 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. – user207421 May 14 '14 at 02:47
  • what do you mean by a bitwise copy of the object? – Horse Voice May 14 '14 at 02:50
  • @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 identical – awksp May 14 '14 at 04:05
  • @TazMan I mean that every bit is copied identically. Surely it's self-explanatory? It's meant to be. – user207421 May 14 '14 at 04:49

4 Answers4

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.

Community
  • 1
  • 1
jxh
  • 69,070
  • 8
  • 110
  • 193
  • 1
    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?? – Horse Voice May 14 '14 at 11:53
  • What you call "deep copy" is what people usually call "shallow copy". – newacct May 14 '14 at 23:32
  • 1
    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. http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#clone%28%29 – wickstopher May 15 '14 at 12:23
  • @cecilg23: The paragraph after of the same doc: "Thus, this method performs a "shallow copy" of this object, not a "deep copy" operation." – jxh May 15 '14 at 19:03
  • 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. – wickstopher May 15 '14 at 19:48
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.

Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249
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;
}
wickstopher
  • 981
  • 6
  • 18
  • What if `first` instance contained other reference variables and lists, would doing first.clone() actually make clones of those too? – Horse Voice May 14 '14 at 12:00
  • I updated my answer to address those questions in more detail. Let me know if that makes it more clear! – wickstopher May 14 '14 at 14:40
  • But how is it better than `MyObj` having a "copy constructor" (a constructor that takes a `MyObj`), and using that instead? – newacct May 15 '14 at 06:27
  • 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. – wickstopher May 15 '14 at 12:13
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();
  }
...
Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275