There are two popular approaches. One is to provide a clone
method as you mentioned, like so.
public class C implements Cloneable {
@Override public C clone() {
try {
final C result = (C) super.clone();
// copy fields that need to be copied here!
return result;
} catch (final CloneNotSupportedException ex) {
throw new AssertionError();
}
}
Pay attention to the "copy fields ... here!" part. The initial result
is only a shallow copy, meaning that if there's a reference to an object, both the original and result
will share the same object. For example, if C
contains private int[] data
you'd probably want to copy that.
...
final C result = (C) super.clone();
result.data = data.clone();
return result;
...
Note that you don't need to copy primitive fields, as their content is already copied, or immutable objects, as they can't change anyways.
The second approach is to provide a copy constructor.
public class C {
public C(final C c) {
// initialize this with c
}
}
Or a copy factory.
public class C {
public static C newInstance(final C c) {
return new C(c);
}
private C(final C c) {
// initialize this with c
}
}
Both approaches have their respective properties. clone
is nice because its a method, so you don't have to know the exact type. In the end, you should always end up with a "perfect" copy. The copy constructor is nice because the caller has a chance to decide, as can be seen by the Java Collections.
final List c = ...
// Got c from somewhere else, could be anything.
// Maybe too slow for what we're trying to do?
final List myC = new ArrayList(c);
// myC is an ArrayList, with known properties
I recommend choosing either approach, whichever suits you better.
I'd use the other approaches, like reflective copying or immediate serializing/deserializing, in unit tests only. To me, they feel less appropriate for production code, mainly because of performance concerns.