How can I create a copy of my data type I created in Java?
If I have a class:
public class MyType
{
private List<Integer> data;
private boolean someFlag;
public MyType(List<Integer> myData, boolean myFlag)
{
this.data = myData;
thi开发者_Python百科s.myFlag = someFlag;
}
}
Now, if I create an instance of MyType, how do I do a deep copy of it? I don't want the new object to point to the old reference, but an entirely new instance.
Is this a case when I should implement the Cloneable interface, or is that a used for shallow copies?
I can't just do:
MyType instance1 = new MyType(someData, false);
MyType instance2 = new MyType(instance1.getData(), instance1.getFlag());
I'm concerned about new instances of MyType pointing to the same reference for its "data" variable. So I need to copy it entirely.
So, if I have an existing object:
MyType someVar = new MyType(someList, false);
// Now, I want a copy of someVar, not another variable pointing to the same reference.
Can someone point me in the right direction?
First: Your code sample has some naming issues: is it myFlag or someFlag?
Many developers will abstain from Cloneable and just create a copy constructor for a class when deep copies are needed:
public class MyType {
private boolean myFlag;
private List<Integer> myList;
public MyType(MyType myInstance) {
myFlag = myInstance.myFlag;
myList = new ArrayList<Integer>(myInstance.myList);
}
}
Copy constructors quite common, and can be found in many of the Collections implementations. I prefer them over implementing Cloneable for reasons of clarity. It's also worth noting that even the mighty Joshua Bloch says in Effective Java (second edition page 61) that copy constructors have many advantages over Cloneable/clone.
- They don't rely on a risk-prone extralinguistic object creation mechanism
- They don't demand unenforceable adherence to thinly documented conventions
- They don't conflict with the proper use of final fields
- They don't throw unnecessary checked exceptions
- They don't require casts.
If you don't own his book, get it!
You can make all classes in your object graph implement Cloneable
and provide manual cloning. Since in your case it's only one list (i.e. a very small object graph), you'd better use the copy-constructor:
List newData = new ArrayList(data)
But remember that in that case the contents of the list will still be the same objects, so it won't be a real deep copy. In your case these are Integer
s, so no big deal. But if you change it, be careful.
If you need to clone bigger object graphs, then, in two steps:
- make your class implement the
Serializable
interface - use apache commons-lang
SerializationUtils.clone(yourObject)
It makes a deep copy using the serialization mechanisms in java.
Alternatively, you can use this library - it does not require the Serializable
interface and makes deep copies using reflection.
You should implement Cloneable
. You define what a "copy of your type" exactly means. Sometimes it is required to have a type containing a field whose content remains the same within multiple copies (==reference to the same object in all copied instances)
You have to take care on your own that all the fields are actually copied to a new instance. Primitive datatypes like int, long, etc. are copied as they are directly stored, they never contain references.
If you have fields to object references of what type ever, you need to find a mechanism to create a copy of each of them.
Generally, you do have a shallow copy after calling .clone()
. If (and only if) all the types used in your class are themselves implementing Cloneable correctly, you get a fully recursive deep copy.
According to JavaDoc (Object.clone()) Clonable
means the following:
x.clone() != x && x.clone().getClass() == x.getClass() && x.clone().equals(x)
Remember that this is the general intent, and this is not a mandatory contract
your class MyType must implement Cloneable. then you can call someVar.clone()
Implement ICloneable
精彩评论