All approaches to copy objects in Java have serious flaws:
Clone
- The clone() method is protected, so you can't call it directly unless the class in question overrides it with a public method.
- clone() doesn't call the constructor. Any constructor. It will allocate memory, assign the internal
class field (which you can read via getClass()) and copy the fields of the original.
For more issues with clone(), see item 11 of Joshua Bloch's book "Effective Java, Second Edition"
Serialize
Serialize is even worse; it has many of the flaws of clone() and then some. Joshua has a whole chapter with four items for this topic alone.
My Solution
My solution is add a new interface to my projects:
public interface Copyable<T> {
T copy ();
T createForCopy ();
void copyTo (T dest);
}
The code looks like this:
class Demo implements Copyable<Demo> {
public Demo copy () {
Demo copy = createForCopy ();
copyTo (copy);
return copy;
}
public Demo createForCopy () {
return new Demo ();
}
public void copyTo (Demo dest)
super.copyTo (dest);
...copy fields of Demo here...
}
}
Unfortunately, I have to copy this code to all my objects but it's always the same code, so I can use an Eclipse editor template. Advantages:
- I can decide which constructor to call and how to initialize which field.
- Initialization happens in a deterministic order (root class to instance class)
- I can reuse existing objects and overwrite them
- Type safe
- Singletons stay singletons
For standard Java types (like collections, etc), I use a utility class which can copy those. The methods have flags and callbacks, so I can control how deep a copy should be.