I'm wondering if there is a recommended way of doing deep clone/copy of instance in java.
I have 3 solutions in mind, but I can have miss some, and I'd like to have your opinion
edit: include Bohzo propositon and refine question: it's more about deep cloning than shallow cloning.
code the clone by hand properties after properties and check that mutable instances are cloned too.
pro:
- control of what will be performed
- quick execution
cons:
- tedious to write and maintain
- bug prone (copy/paste failure, missing property, reassigned mutable property)
With your own reflection tools or with an external helper (like jakarta common-beans) it is easy to write a generic copy method that will do the job in one line.
pro:
- easy to write
- no maintenance
cons:
- less control of what happens
- bug prone with mutable object if the reflection tool does not clone sub objects too
- slower execution
Use a framework that do it for you, like :
commons-lang SerializationUtils
Java Deep Cloning Library
Dozer
Kryo
pro:
- same as reflection
- more control over what will be exactly be cloned.
cons:
- every mutable instance is fully cloned, even at the end of the hierarchy
- could be very slow to execute
javassit, BCEL or cglib might be use to generate a dedicated cloner as fast as one hand writed. Someone knows a lib using one of these tools for this purpose ?
What I have missed here ?
Which one would you recommend ?
Thanks.
According to the benchmark test, the fastest way to deep clone an object in javascript is to use lodash deep clone function since Object. assign supports only shallow copy.
To create the deep copy of an object, you have to override clone method. Shallow copy is preferred if an object has only primitive fields. Deep copy is preferred if an object has references to other objects as fields. Shallow copy is fast and also less expensive.
clone() is indeed a shallow copy. However, it's designed to throw a CloneNotSupportedException unless your object implements Cloneable . And when you implement Cloneable , you should override clone() to make it do a deep copy, by calling clone() on all fields that are themselves cloneable.
commons-lang SerializationUtils - using serialization - if all classes are in your control and you can force implementing Serializable
.
Java Deep Cloning Library - using reflection - in cases when the classes or the objects you want to clone are out of your control (a 3rd party library) and you can't make them implement Serializable
, or in cases you don't want to implement Serializable
.
commons-beanutils BeanUtils - in most cases.
Spring BeanUtils - if you are already using spring and hence have this utility on the classpath.
I deliberately omitted the "do-it-yourself" option - the API's above provide a good control over what to and what not to clone (for example using transient
, or String[] ignoreProperties
), so reinventing the wheel isn't preferred.
Joshua Bloch's book has a whole chapter entitled "Item 10: Override Clone Judiciously" in which he goes into why overriding clone for the most part is a bad idea because the Java spec for it creates many problems.
He provides a few alternatives:
Use a factory pattern in place of a constructor:
public static Yum newInstance(Yum yum);
Use a copy constructor:
public Yum(Yum yum);
All of the collection classes in Java support the copy constructor (e.g. new ArrayList(l);)
Since version 2.07 Kryo supports shallow/deep cloning:
Kryo kryo = new Kryo();
SomeClass someObject = ...
SomeClass copy1 = kryo.copy(someObject);
SomeClass copy2 = kryo.copyShallow(someObject);
Kryo is fast, at the and of their page you may find a list of companies which use it in production.
Use XStream toXML/fromXML in memory. Extremely fast and has been around for a long time and is going strong. Objects don't need to be Serializable and you don't have use reflection (although XStream does). XStream can discern variables that point to the same object and not accidentally make two full copies of the instance. A lot of details like that have been hammered out over the years. I've used it for a number of years and it is a go to. It's about as easy to use as you can imagine.
new XStream().toXML(myObj)
or
new XStream().fromXML(myXML)
To clone,
new XStream().fromXML(new XStream().toXML(myObj))
More succinctly:
XStream x = new XStream();
Object myClone = x.fromXML(x.toXML(myObj));
For complicated objects and when performance is not significant i use gson to serialize the object to json text, then deserialize the text to get new object.
gson which based on reflection will works in most cases, except that transient
fields will not be copied and objects with circular reference with cause StackOverflowError
.
public static <ObjectType> ObjectType Copy(ObjectType AnObject, Class<ObjectType> ClassInfo)
{
Gson gson = new GsonBuilder().create();
String text = gson.toJson(AnObject);
ObjectType newObject = gson.fromJson(text, ClassInfo);
return newObject;
}
public static void main(String[] args)
{
MyObject anObject ...
MyObject copyObject = Copy(o, MyObject.class);
}
Depends.
For speed, use DIY. For bulletproof, use reflection.
BTW, serialization is not the same as refl, as some objects may provide overridden serialization methods (readObject/writeObject) and they can be buggy
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With