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.