Should Java's clone method still be avoided?

Just wandering if the clone issue is fixed.
I’ve not heard of it since it’s last mentioned that there was going to be a fix for Mustang, but that was several years ago.

Could you explain the bug please? I’m not aware of it.

http://www.javapractices.com/Topic71.cjp
http://www.artima.com/intv/issues3.html

I consider this a bug.

I’m not sure I see the problem. The first link states that “Clone is a real mess”, but doesn’t explain why. It then goes on to discuss problems with an alternative to clone(). Also, from the link

[quote]Besides the fact that it’s misspelled, Cloneable doesn’t contain the clone method. That means you can’t test if something is an instance of Cloneable, cast it to Cloneable, and invoke clone. You have to use reflection again, which is awful. That is only one problem, but one I’d certainly solve.
[/quote]
Eh? clone() is defined by Object. There’s no need to cast to Cloneable or use reflection.

The second link just says the implementing clone() is tricky, but again no explanation why.

Am I just being dim?

As I remember the problem was that memory being copied from one place to another via clone wasn’t being done properly. This was a good few years back.
It was even discussed en mass on these forums. Some members even mentioned clone() was slower than creating a new object with the current object’s properties.

Interesting, I’ve never heard of that before. Do you have any links? The forum search treats a search for “.clone()” the same as “clone”, and so spits out 14 pages of people saying “I want to make a tetris/snake/pong/whatever clone” that I haven’t the fortitude to search through manually.

Use the following method to clone an object:

/**
 * Clone utility, to make deep copies of serializable objects. Found on
 * http://www.javaworld.com/javaworld/javatips/jw-javatip76-p2.html
 * 
 * @author  king
 * @since   November 18, 2004
 */
public final class ObjectCloner {
  
  /**
   * To allow nobody to create an object cloner object. 
   */
  private ObjectCloner() {
    // so that nobody can accidentally create an ObjectCloner object
  }

  /**
   * Returns a deep copy of a serializable object.
   * 
   * @param object  The object to be cloned.
   * @return  The cloned object or null, if cloning didn't work.
   */
  public static Object deepCopy(Object object) {
    ObjectOutputStream oos = null;
    ObjectInputStream ois = null;
    try {
      ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
      oos = new ObjectOutputStream(bos); 
      // serialize and pass the object
      oos.writeObject(object); 
      oos.flush(); 
      ByteArrayInputStream bin = new ByteArrayInputStream(bos.toByteArray()); 
      ois = new ObjectInputStream(bin); 
      // return the new object
      return (Serializable)ois.readObject(); 
    } 
    catch (IOException e) {
      return null;
    } 
    catch (ClassNotFoundException e) {
      return null;
    }
    finally {
      try {
        oos.close();
        ois.close();
      }
      catch (IOException e) {
        return null;
      }
    }
  }
}

(only works on Serializable objects of course, and is several orders of magnitude slower and vastly more memory intensive)

Cas :slight_smile:

It’s a good idea to pick up a copy of Joshua Bloch’s “Effective Java Programming Language Guide” if you don’t have it already. There’s a lot of great advice in there and the section on the Cloneable interface will tell you everything you need to know about it.

The trouble with clone() is that it only does a shallow clone - only the primitives fields belonging to the object are copied but the Object fields are only copied by reference. This is documented though so I’m not sure that it’s considered a bug.

It means that a ‘cloned’ object actually shares the arms and legs of its brother clone. Maybe it should be renamed to siameseClone()!

Serializing and then De-serializing fixes this like Kingaschi explains, but I think you can also do a recursive clone too.

Keith

The problem with the Cloneable interface is, that it really doesn’t do anything. You still need to implement your clone() method from hand. Cloneable Javadoc:

[quote]By convention, classes that implement this interface should override Object.clone (which is protected) with a public method. See Object.clone() for details on overriding this method.

Note that this interface does not contain the clone method. Therefore, it is not possible to clone an object merely by virtue of the fact that it implements this interface. Even if the clone method is invoked reflectively, there is no guarantee that it will succeed.
[/quote]
So, using the code I attached, all you need to do is to declare the participating classes as Serializable (quick & easy). Then with one line of code, you can obtain the clone:

Object cloneObject = deepCopy(originalObject);

You could write a rather faster method that used Reflection to scan through the fields recursively calling clone() on all sub-objects that support Cloneable. Maybe throw a CloneNotSupported if you come across one that doesn’t. That’d be both a) fast and b) use very little memory c) solve the deep copy problem

Cas :slight_smile:

Would you have to even use reflection? If an Object is Cloneable, it shows that whoever developed the class has put some thought into cloning and hopefully done the right thing in the overridden clone() method. If the Object is not Cloneable, then a CloneNotSupportedException is thrown automatically by Object.clone().