Original URL: http://blog.csdn.net/cool_sti/article/details/21658521
Original English Link: http://javarevisited.blogspot.hk/2014/03/how-to-clone-collection-in-java-deep-copy-vs-shallow.html
Programmers often misuse copy constructors or other methods provided by collection classes (such as list, Set, ArrayList, HashSet) to complete a copy of the collection. It is worth remembering that the copy constructor provided by the collection in Java supports only shallow copies rather than deep copies, which means that objects stored in the original list and clone list remain consistent and point to the same memory address in the Java heap. The reason for this misunderstanding is that it uses collections to make a shallow copy of an immutable object, because the object is immutable, and it is reasonable that two sets point to the same object. It is so, so save the string in the pool, update one of them without affecting other objects. The problem is that when we use the copy constructor of ArrayList to create a clone of the Employee object list, where the employee object is mutable, in this case, if the original collection modifies one of the employee, the change also occurs in the collection of copies, But that's not what we want. In almost all cases, cloning should be independent of the original object. The way to avoid this problem is to use a deep copy collection that recursively copies the object until it accesses a primitive or immutable object. In this article, we will describe a method for deep copy collections, such as ArrayList or HashSet in Java. By the way, if you understand the difference between a shallow copy and a deep copy, you will easily grasp the mechanism of the deep copy collection. Deep copy in Java collection in the following example, we have a collection of variable employee objects, each containing the name and designation fields, and saving them in HashSet. We use the AddAll () method in the Java.util.Collection interface to create a copy of this collection. After that, we modify the designation field of each employee object in the original collection, hoping that the change will not affect the Copy collection, but that the solution to this problem is to deeply copy the elements in the collection class.
[Java]View Plaincopy
- Import java.util.Collection;
- Import Java.util.HashSet;
- Import Java.util.Iterator;
- Import Org.slf4j.Logger;
- Import Org.slf4j.LoggerFactory;
- /**
- * Java program to demonstrate copy constructor of Collection provides shallow
- * Copy and techniques to deep clone Collection by iterating over them.
- * @author http://javarevisited.blogspot.com
- */
- Public class Collectioncloningtest {
- private static final Logger Logger = Loggerfactory.getlogger (Collectioncloningclass);
- public static void Main (String args[]) {
- //Deep cloning Collection in Java
- Collection org = new HashSet ();
- Org.add (new Employee ("Joe", "Manager"));
- Org.add (new Employee ("Tim", "Developer"));
- Org.add (new Employee ("Frank", " Developer"));
- //Creating copy of Collection using copy constructor
- Collection copy = new HashSet (org);
- Logger.debug ("Original Collection {}", org);
- Logger.debug ("copy of Collection {}", copy);
- Iterator ITR = Org.iterator ();
- While (Itr.hasnext ()) {
- Itr.next (). Setdesignation ("staff");
- }
- Logger.debug ("Original Collection after modification {}", org);
- Logger.debug ("copy of Collection without modification {}", copy);
- //Deep cloning List in Java
- }
- }
- Class Employee {
- private String name;
- private String designation;
- Public Employee (string name, string designation) {
- this.name = name; this.designation = designation;
- }
- Public String getdesignation () {
- return designation;
- }
- public void Setdesignation (String designation) {
- this.designation = designation;
- }
- Public String GetName () {
- return name;
- }
- public void SetName (String name) {
- this.name = name;
- }
- @Override public String toString () {
- return String.Format ("%s:%s", name, designation);
- }
- }
Output:
[HTML]View Plaincopy
- -Original Collection [Joe:manager, Frank:developer, Tim:developer]
- -Copy of Collection [Joe:manager, Frank:developer, Tim:developer]
- -Original Collection after modification [Joe:staff, Frank:staff, Tim:staff]
- -Copy of Collection without modification [Joe:staff, Frank:staff, Tim:staff]
It is clear that the employee object that modifies the original collection (that is, the Modify designation field is "Staff") is also reflected in the Copy collection, because the clone is a shallow copy that points to the same employee object in the heap. To fix this problem, we need to iterate through the set depth copy of all the employee objects, and before that we need to overwrite the Clone method for the Employee object. 1) Let the employee class implement the Cloneable interface, 2) Add the following clone () method to the employee class;
[Java]View Plaincopy
- @Override
- Protected Employee Clone () {
- Employee clone = null;
- try{
- Clone = (Employee) super.clone ();
- }catch (Clonenotsupportedexception e) {
- throw New RuntimeException (e); //won ' t happen
- }
- return clone;
- }
3) Use the following code to replace the copy constructor with a deep copy in Java;
[Java]View Plaincopy
- collection<employee> copy = new Hashset<employee> (Org.size ());
- iterator<employee> Iterator = Org.iterator ();
- while (Iterator.hasnext ()) {
- Copy.add (Iterator.next (). Clone ());
- }
4) Run the same code for the modified collection, and you will get different output:
[HTML]View Plaincopy
- -Original Collection after modification [Joe:staff, Tim:staff, Frank:staff]
- -Copy of Collection without modification [Frank:developer, Joe:manager, Tim:developer]
It can be seen that the clone and the original set are independent of each other, pointing to different objects respectively. This is how Java clones all the contents of a collection, and now we understand that the various copy constructors in the collection class, such as the AddAll () method in list or set, implement only a shallow copy of the collection, that is, the collection of the original collection and the copy point to the same object. This also requires that any objects be stored in the collection, and deep copy operations must be supported. PS: The code execution in the original blog may encounter some problems, but the key is that the middle thought is very important. Links: How to create immutable Class and Object in java-tutorial exampledifference between deep copy vs Shadow cloning in Ja Vacollection Interview Questions Answershow Clone method works in Java
"Go" Java How to Clone collections--deep copy ArrayList and HashSet