Copying objects in Java
There are two ways of creating copies of objects (and arrays) in Java:
1. Shallow Copy
2. Deep Copy
What is "Deep Copy"?
A deep copy copies all fields, and makes copies of inner objects as well (unlike creating a copy of the memory address of the inner object). A deep copy occurs when an object, along with all the objects to which it refers, is copied as a whole. After a deep copy, if we change the property of the inner object in the copied object, it will not affect the respective property of the inner object in the original object.
How can we create a deep copy of an object?
We can achieve deep copy in 3 ways.
1. Serialize and de-serialize
2. Clone the Object correctly
3. Copy Constructor
If the object which we need to deep copy is simple, we can go for either the copy constructor approach or we can implement the clone correctly. But in most cases we will need to deep copy various objects of various complexities. The object graph may be much more complex which results in increased complexity of both the copy constructor and the clone methods. In this case we can go for the serialization approach. By using serialization, we can create deep copies of any object s that adhere to a set of rules by just one function.
Rules for deep copy using serialization to work correctly
1. All classes in the object graph should be serializable
2. Serialization should not be overridden such that new instances are not created, e.g. for singletons.
How to implement serialization?
We need to use a common utility class and provide a static method that will serialize and de-serialize the object, thus creating a deep copy of that object, and then return the copy. Serialization and deserialization of the object ensures that all the classes in the object graph are recreated in a new heap location.
Sample code illustrating deep copy through serialization/deserialization:
What is "Shallow Copy"?
When we clone an object, only the values of that object get copied. The newly created object has an exact copy of the values in the original object. If any of the fields of the original object store references to other objects, then, just the reference addresses are copied (i.e., only the memory address is copied). So, manipulating the property of the inner object in a copied object after a shallow copy will result in the modification of the respective property of the inner object in the original object as well, as both points to the same address in the heap.
Sample code (with output) illustrating shallow copy:
//Code to run application
Note here, that the change made to the value of "address" in the cloned object (s2) changed the value of "address" in the original object (s1) as well, as they both point to same object in the heap.
How Deep Copy can be implemented effectively in the above example:
1. Override clone Correctly
In the above case if we override the clone method in the School correctly we can create a deep copy.
2. Copy Constructor
We can provide a copy constructor in the School that will return a deep copy of the school. In school class provide the copy constructor
And use copy constructor to provide the copy of the object
3. Serialize and de-serialize
Use the CommonUtil class (already explained above) to get the copy:
The output of all three deep copy methods is:
Note here, that the change made to the value of "address" in the cloned object (s2) does not change the value of "address" in the original object (s1).
You can also use some third party libraries to create deep copies. Dozer and Kryo are two great libraries that serve this purpose. There is also Apache Commons that provides SerializationUtils.
1) Whenever we copy a Collection of objects we should always go for deep copy.
2) Copy method in the Collections class creates a shallow copy, and hence, modifying the objects in the copied collection will modify the object in the actual collection.
This post is written by Jerin Joseph. He is a freelance writer, loves to explore latest features in Java technology.