This question already has answers here:
How do I copy an object in Java?
(23 answers)
Closed 9 years ago.
I am having difficulties understanding the concept of "deep copy" in Java.
Assuming I had a class "myClass" with various parameters in it. I tried writing a method "copy" which was supposed to return a deep copy of such class as:
public myClass copy() {
myClass deepCopy = new myClass();
deepCopy.varA = varA;
deepCopy.varB = varB;
return deepCopy;
}
Can somebody confirm whether this is indeed "deep copying" or if I am doing something wrong?
Thanks!
If you don’t want to implement deep copy yourselves then you can go for serialization. It does implements deep copy implicitly and gracefully handling cyclic dependencies.
A nice article about Deep Copy, Clone and Shallow Copy can be found here.
Only If:
Class "myClass" only contains varA and varB.
Class "myClass" has no superclass.
Variables varA and varB are of an elementary type (ie. String, int, long, ....). Otherwise you'll have to apply the same copying process to them too.
In deep copy When the copied object contains some other object its references are copied recursively
see more at here
A deep copy occurs when an object is copied along with the objects to which it refers.
If suppose there is a MainObject1 of MainObject type having fields "field1" of int type, and "ContainObject1" of ContainObject type. When you do a deep copy of MainObject1, MainObject2 is created with "field3" containing the copied value of "field1" and "ContainObject2" containing the copied value of ContainObject1. So any changes made to ContainObject1 in MainObject1 will not be reflected in MainObject2.
In your implementation, if you are trying to simulate deep copy, then you should have only these two variables : varA and varB in your class of primitive type.
This would only be a deep copy if varA and VarB were primitive types. If they are reference types than your new object will point at the same instances of these classes as the original.
An easy way to implement deep copy is via serialization. Apache commons lang provides a utility method for this (SerializationUtils.clone( foo ) ).
It does however requires that all the objects are serializable.
If this is not the case for you XStream can be used for deep cloning with minimal development effort.
http://x-stream.github.io/
Observe output of following program.
1> See output without clone() method. Remove clone() method from following program. (example of shallow copy)
2> See output with clone() method. (Example Deep copy. See ArrayList object's output)
import java.util.ArrayList;
import java.util.List;
public class DeepCopy implements Cloneable {
private List<String> hobbiesList;
private int age;
private String name;
private float salary;
public static void main(String[] args) throws CloneNotSupportedException {
DeepCopy original = new DeepCopy();
original.name="AAA";
original.age=20;
original.salary=10000;
original.hobbiesList = new ArrayList<String>();
original.hobbiesList.add("Cricket");
original.hobbiesList.add("Movies");
original.hobbiesList.add("Guitar");
original.hobbiesList.add("Eating");
DeepCopy cloned = (DeepCopy) original.clone();
System.out.println("original:="+original);
System.out.println("cloned :="+cloned);
System.out.println("After adding two more hobbies in 'original' which untimately reflected in 'cloned'");
cloned.name="BBB";
cloned.age=27;
cloned.salary=18237;
cloned.hobbiesList.add("Trecking");
System.out.println("original :="+original);
System.out.println("cloned changed:="+cloned);
}
#Override
protected Object clone() throws CloneNotSupportedException {
DeepCopy clone = (DeepCopy)super.clone();
clone.hobbiesList = new ArrayList<String>(clone.hobbiesList);
return clone;
}
#Override
public String toString() {
return "My name is (String)"+name + " having age (int)"+age+". I earned (float)"+salary+" and hobbies are (ArrayList)"+hobbiesList;
}
}
Related
This question already has answers here:
Copy of arraylist keeps getting modified to the values of the original
(4 answers)
Closed 6 years ago.
I am trying to copy the contents of an ArrayList to another and change the contents of copy. I don't want this to be reflected in the original.
I checked on SO and made changes accordingly, still the same issue. Can someone help? I am sharing the code below:
private ArrayList<CustVoiceListObject> FilterApprovedWorkFromList() {
ArrayList<CustVoiceListObject> arrayListCopy = new ArrayList<>(arrayListCustVoice);
for(int i =0; i<arrayListCopy.get(position).getPackageArray().size();i++)
{
if(!arrayListCopy.get(position).getPackageArray().get(i).getPackageApproved().equals("Y"))
{
arrayListCopy.get(position).getPackageArray().remove(i);
i--;
}
}
return arrayListCopy;
}
While debugging, when it is about to return, I check the original arraylist arrayListCustVoice but this is also modified similar arrayListCopy
What am I missing?
UPDATE [Following the suggestions][This questions hence is not duplicate!]
This is my modified code:
private ArrayList<CustVoiceListObject> FilterApprovedWorkFromList() {
ArrayList<CustVoiceListObject> arrayListCopy = (ArrayList<CustVoiceListObject>) arrayListCustVoice.clone();
for(int i =0; i<arrayListCopy.get(position).getPackageArray().size();i++)
{
if(!arrayListCopy.get(position).getPackageArray().get(i).getPackageApproved().equals("Y"))
{
arrayListCopy.get(position).getPackageArray().remove(i);
i--;
}
}
return arrayListCopy;
}
In fact I have implemented Cloneable to my original class, still I am facing the same problem.
Update 2 [Research Conclusion]
I came across this link
In my case, there are 2 classes. The 2nd is subset of first. Pasting below:
public class CustVoiceListObject implements Cloneable {
private String txtSource, txtCustComment, txtCustOk, txtRepeat;
private int numberOfPackages, complaintSerial;
private ArrayList<CustomerVoicePackageListObject> packageArray;
private Double totalAmount;
//getters & setters & constructors
#Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
Class 2:
public class CustomerVoicePackageListObject implements Cloneable {
public String packageCategory;
public String packageName;
public String partUsageFlag;
public String laborUsageFlag;
public String status;
public String isApproved;
//getters & setters & constructors
#Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
The .clone() must link to the clone() of the CLASS, not elsewhere. And if it correctly does, it will provoke for taking measure to address the exception as per my implementing the clone() in each individual class.
So this is what I did, modified that for loop to this:
private CustVoiceListObject FilterApprovedWorkFromList() {
//Observe the change here. It's no more ArrayList, it's Class type
CustVoiceListObject arrayListCopy = null;
try {
arrayListCopy = (CustVoiceListObject) arrayListCustVoice.get(position).clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
for(int i =0; i<arrayListCopy.getPackageArray().size();i++)
{
if(!arrayListCopy.getPackageArray().get(i).getPackageApproved().equals("Y"))
{
arrayListCopy.getPackageArray().remove(i); //this is ArrayList<ClassType>. Nested class objects.
arrayListCopy.setTxtCustOk("OKOK"); //within the class
i--;
}
}
return arrayListCopy;
}
The result was the changes within the packageArray reflected in both (failure) BUT, changes in txtCustOk within the basic class, changed in copy, not in original (success). That means, problem is in cloning with ArrayList
So deep cloning requires satisfaction of following rules:
1.No need to separately copy primitives.
2.All the member classes in original class should support cloning and in clone method of original class in context should call
super.clone() on all member classes.
3.If any member class does not support cloning then in clone method, one must create a new instance of that member class and copy all its
attributes one by one to new member class object. This new member
class object will be set in cloned object.
So my aim is to get rid of ArrayList and shift those elements to this class. This is painful. Looking for an easy alternative.
The problem is that your elements of the original ArrayList are reference values so you just copy the references to those objects but not the objects themselves (which seem to be another kind of arrays).
Have a look at this question which essentially deals with the same kind of problem.
The copy operation copied the original list - but not the elements of the list.
That is, if oldList had the following Person objects:
oldList: John, Jane, Jude, Joe
And you copied oldList to newList:
oldList: John, Jane, Jude, Joe
newList: John, Jane, Jude, Joe
And then deleted John from newList:
oldList: John, Jane, Jude, Joe
newList: Jane, Jude, Joe
you can see that they are two distinct lists. But you're not changing the lists, you're changing the objects inside the list. If Joe's name got changed to Jim, you'd have:
oldList: John, Jane, Jude, Jim
newList: Jane, Jude, Jim
You have only done what is called a "shallow" copy. You want to do a "deep" copy, as shown here.
Edit (to "Update 2" in question)
Your research didn't go far enough, I'm afraid. In your (new) Class 1:
public class CustVoiceListObject implements Cloneable {
// ints, Doubles, Strings
private ArrayList<CustomerVoicePackageListObject> packageArray;
//getters & setters & constructors
#Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
you simply returned super.clone() - letting Java do all the work for you. This basically does the shallow copy that's causing all your problems! You might as well not have made the object ICloneable. What you missed was that ints, Doubles and even Strings already copy successfully, so you don't need to clone them. But ArrayLists don't clone, so you need to help it along:
#Override
protected Object clone() throws CloneNotSupportedException {
// First copy the easy stuff
CustomerVoiceListObject cvlo = (CustomerVoiceListObject)super.clone();
cvlo.packageArray = new ArrayList<CustomerVoicePackageListObject>(packageArray.size()); // Make sure it's the right size
for (CustomerVoicePackageListObject cvplo: packageArray) {
cvlo.packageArray.add(cvplo.clone());
} // for
return cvlo;
} // clone()
Ok, I just want to copy List<String[]> list to List<String[]> list2. After that I will modify the object in list2 & I want that it won't affect any object int list.
String[] s={"1","2"};
List<String[]> list=new ArrayList<String[]>();
list.add(s);
List<String[]> list2=new ArrayList<String[]>(list);
Collections.copy(list2,list);
list2.get(0)[1]="3";
for (String[] strings : list) {
System.out.println(Arrays.toString(strings));
}
Out put: [1, 3]
Why we change things in list2 & it affect list1?
How to fix it?
Collections.copy() does not perform a deep copy.
It simply copies elements from one collection to another. It is basically the same as the ArrayList constructor, so you do not need to call both.
The first element in both list still refers to the same object. Thus, when you run your code, you are modifying the array in both lists. You can iterate over all your elements, and use Arrays.copyOf on each list item.
Something like this:
private List<String[]> deepCopy(List<String[]> list) {
List<String[]> copy = new ArrayList<String[]>(list.size());
for (String[] element : list) {
copy.add(Arrays.<String> copyOf(element, element.length));
}
return copy;
}
EDIT: Java < 1.6 version:
private List<String[]> deepCopy(List<String[]> list) {
List<String[]> copy = new ArrayList<String[]>(list.size());
for (String[] element : list) {
String[] elementCopy = new String[element.length];
System.arraycopy(element, 0, elementCopy, 0, element.length);
copy.add(elementCopy);
}
return copy;
}
What you are asking for is to copy the collection and clone all the objects it holds. In your case you only have lists of strings. The others already gave you good answers for that. Just as a note. In general it is not that easy, because there is no universal recipe for cloning objects. Because each object in the collection could have references to other objects itself. And those objects could have further references to more objects. So it depends on what you need.
Do you just need to clone the objects in the collection, but not the objects those objects reference to?
This is called "shallow copying".
Or do you need to copy all the objects down the objects reference tree. This is called "deep copying".
Or you might have requirements for something in between. Meaning you only need to copy certain objects.
You see there is no golden bullet which solves everything. That's why it is not implemented in a generic collection class. In some cases cloning might not even be possible if you are dealing with open file handles or other system resources.
But what you can do is, have your classes implement the Cloneable interface. Within the clone() method you can call super.clone() which does already a shallow cloning for you. Everything beyond that needs to be implemented by yourself. Then you only need to call clone() for each object in you collection in order to create the cloned objects.
This is how to implement Cloneable:
class MyClass implements Cloneable {
private int a;
private int b;
private MyClass c;
#Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
Calling clone() would give you a copy of your MyClass-object. That means a and b would be copies as well as the reference to object c. But only the reference, not the object c itself. If you need that, you need to do something like this:
#Override
public Object clone() throws CloneNotSupportedException {
MyClass clone = (MyClass)super.clone();
clone.c = (MyClass2)c.clone();
return clone;
}
Here is a more detailed explanation for shallow and deep copying and the Cloneable interface:
http://javapapers.com/core-java/java-clone-shallow-copy-and-deep-copy/
I want to ask you how can i copy firstClass objects to secondClass objects?
Is this possible to figure it out by using clone()?
The situation looks like this:
I have a class f.x. firstClass. And I need to clone firstClass objects to secondClass objects (and these cloned objects must be stored into array)
Thanks
EDITED:
sorry for a little information. But my task looks like this:
Write a Garage class whose objects can hold up to some number of Vehicle objects in an
array. Make Garage a Cloneable type, and write a proper clone method for it. Write a Garage.main
method to test it.
It's not cloning. If you have two unrelated classes, the best you can do is write a constructor for SecondClass that takes FirstClass object as an argument and writes all the values into the proper fields:
public SecondClass (FirstClass source){
this.valueA = source.getValueA();
this.valueB = source.getBValue();
this.valueC = source.getProperCValue();
...
}
By convention, Object.clone() method and its overrides should always return an object of the original type.
x.clone().getClass() == x.getClass()
So it should be impossible to create an object of different type if clone() is properly implemented and used.
something like this?!
class Foo{
private String bar;
public Object clone(){
Foo f=new Foo();
f.setBar(this.bar);
//filling and copy the f attributes
guys.add(f);
}
///
private final static List<Foo> guys=new ArrayList<>();
///
}
Hi I have a enum array and it is a field of my class. And I am implementing clone method of this class. But I have some ideas about copying array of enums but what is the formal way of copying an enum array ?
public enum StateEnum {
START, PLAY, PAUSE , STOP
}
class MyClass{
StateEnum[] stateEnums;
public Object clone(){
MyClass copyClass = new MyClass();
// copy enums
}
}
Enum values are (or should be) immutable, so you don't need to copy them.
You can just make a shallow copy of the array by calling System.arraycopy().
As said by SLaks, use the System.arraycopy to clone your array. Further, the
MyClass copyClass = new MyClass();
should be replaced by
MyClass copyClass = (MyClass)super.clone();
The reason for this is explained in this article in full detail, where the end of page 2 discusses the common pitfalls while implementing a clone method
I'm trying to clone an instance of a custom class I made called CSP. I have one instance called csp and I want to make a clone of csp called cspclone. Here is what I'm using to do that:
CSP cspclone = new CSP((csp.x).clone(), (csp.d).clone(), (csp.c).clone());
For some reason though when I pass cspclone to a method that modifies it csp gets modified also as if I forgot the .clone() functions but I didn't! Why is this happening?!
Override the clone method in CSP:
public class CSP {
private String aField;
private int[] array;
private int[][] twoDArr;
private List<ALContent> list; //here ALContent also needs to override clone properly
#Override
public Object clone() {
CSP clone = new CSP();
clone.aField = this.aField;
clone.array = new int[this.array.length];
System.arraycopy(this.array, 0, clone.array, 0, this.array.length);
clone.list = new ArrayList<ALContent>();
for(ALContent content : this.list) {
clone.list.add(content.clone()); //make sure you add the clone of the content
}
clone.twoDArr = new int[this.twoDArr.length][];
for(int i=0; i<this.twoDArr.length; i++) {
clone.twoDArr[i] = new int[this.twoDArr[i].length];
System.arraycopy(this.twoDArr[i], 0, clone.twoDArr[i], 0, this.twoDArr[i].length);
}
return clone;
}
}
Then you can do:
CSP csp = new CSP();
CSP cspClone = (CSP) csp.clone();
If your properties of array type use System.arraycopy
According to http://download.oracle.com/javase/1.3/docs/api/java/lang/Object.html#clone%28%29
this method creates a new instance of the class of this object and initializes all its fields with exactly the contents of the corresponding fields of this object, as if by assignment; the contents of the fields are not themselves cloned. Thus, this method performs a "shallow copy" of this object, not a "deep copy" operation.
You might have to override the clone method and clone() a reference type attribute within the object (i.e., perform deep copy operation).
To solve your problem you need deep cloning. The default clone method does a shallow copy. See Object.clone().
Here are some approaches. All have advantages and drawbacks.
Override: Override the clone() method.
Serialization: Write the object to a stream and a read it back from the stream.
Reflection: Here is a tutorial on reflection.
Use a deep close library, such as Java Deep-Cloning library.
Here are several other stackoverflow discussions of cloning.
Java: recommended solution for deep cloning/copying an instance
Deep clone utility recomendation
How to clone ArrayList and also clone its contents?