Consider the code below:
DummyBean dum = new DummyBean();
dum.setDummy("foo");
System.out.println(dum.getDummy()); // prints 'foo'
DummyBean dumtwo = dum;
System.out.println(dumtwo.getDummy()); // prints 'foo'
dum.setDummy("bar");
System.out.println(dumtwo.getDummy()); // prints 'bar' but it should print 'foo'
So, I want to copy the dum
to dumtwo
and change dum
without affecting the dumtwo
. But the code above is not doing that. When I change something in dum
, the same change is happening in dumtwo
also.
I guess, when I say dumtwo = dum
, Java copies the reference only. So, is there any way to create a fresh copy of dum
and assign it to dumtwo
?
I use Google's JSON library to serialize it then create a new instance of the serialized object. It does deep copy with a few restrictions:
there can't be any recursive references
it won't copy arrays of disparate types
arrays and lists should be typed or it won't find the class to instantiate
you may need to encapsulate strings in a class you declare yourself
I also use this class to save user preferences, windows and whatnot to be reloaded at runtime. It is very easy to use and effective.
import com.google.gson.*;
public class SerialUtils {
//___________________________________________________________________________________
public static String serializeObject(Object o) {
Gson gson = new Gson();
String serializedObject = gson.toJson(o);
return serializedObject;
}
//___________________________________________________________________________________
public static Object unserializeObject(String s, Object o){
Gson gson = new Gson();
Object object = gson.fromJson(s, o.getClass());
return object;
}
//___________________________________________________________________________________
public static Object cloneObject(Object o){
String s = serializeObject(o);
Object object = unserializeObject(s,o);
return object;
}
}
Just follow as below:
public class Deletable implements Cloneable{
private String str;
public Deletable(){
}
public void setStr(String str){
this.str = str;
}
public void display(){
System.out.println("The String is "+str);
}
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
and wherever you want to get another object, simple perform cloning. e.g:
Deletable del = new Deletable();
Deletable delTemp = (Deletable ) del.clone(); // this line will return you an independent
// object, the changes made to this object will
// not be reflected to other object
To do that you have to clone the object in some way. Although Java has a cloning mechanism, don't use it if you don't have to. Create a copy method that does the copy work for you, and then do:
dumtwo = dum.copy();
Here is some more advice on different techniques for accomplishing a copy.
class DB {
private String dummy;
public DB(DB one) {
this.dummy = one.dummy;
}
}
If you can add an annotation to the source file, an annotation processor or code generator like this one can be used.
import net.zerobuilder.BeanBuilder
@BeanBuilder
public class DummyBean {
// bean stuff
}
A class DummyBeanBuilders
will be generates, which has a static method dummyBeanUpdater
to create shallow copies, the same way as you would do it manually.
DummyBean bean = new DummyBean();
// Call some setters ...
// Now make a copy
DummyBean copy = DummyBeanBuilders.dummyBeanUpdater(bean).done();
Use gson
for duplicating an object.
public static <T>T copyObject(Object object){
Gson gson = new Gson();
JsonObject jsonObject = gson.toJsonTree(object).getAsJsonObject();
return gson.fromJson(jsonObject,(Type) object.getClass());
}
Assume I have an object person
.So
Person copyPerson = copyObject(person);
Note: The performance is much slower.
public class MyClass implements Cloneable {
private boolean myField= false;
// and other fields or objects
public MyClass (){}
@Override
public MyClass clone() throws CloneNotSupportedException {
try
{
MyClass clonedMyClass = (MyClass)super.clone();
// if you have custom object, then you need create a new one in here
return clonedMyClass ;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return new MyClass();
}
}
}
and in your code:
MyClass myClass = new MyClass();
// do some work with this object
MyClass clonedMyClass = myClass.clone();
Deep Cloning is your answer, which requires implementing the Cloneable
interface and overriding the clone()
method.
public class DummyBean implements Cloneable {
private String dummy;
public void setDummy(String dummy) {
this.dummy = dummy;
}
public String getDummy() {
return dummy;
}
@Override
public Object clone() throws CloneNotSupportedException {
DummyBean cloned = (DummyBean)super.clone();
cloned.setDummy(cloned.getDummy());
// the above is applicable in case of primitive member types like String
// however, in case of non primitive types
// cloned.setNonPrimitiveType(cloned.getNonPrimitiveType().clone());
return cloned;
}
}
You will call it like this
DummyBean dumtwo = dum.clone();
Add Cloneable
and below code to your class
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
Use this clonedObject = (YourClass) yourClassObject.clone();
Yes. You need to Deep Copy your object.
Basic: Object Copying in Java.
Let us Assume an object- obj1
, that contains two objects, containedObj1 and containedObj2.
shallow copying:
shallow copying creates a new instance
of the same class and copies all the fields to the new instance and returns it. Object class provides a clone
method and provides support for the shallow copying.
Deep copying:
A deep copy occurs when an object is copied along with the objects to which it refers. Below image shows obj1
after a deep copy has been performed on it. Not only has obj1
been copied, but the objects contained within it have been copied as well. We can use Java Object Serialization
to make a deep copy. Unfortunately, this approach has some problems too(detailed examples).
Possible Problems:
clone
is tricky to implement correctly.
It's better to use Defensive copying, copy constructors(as @egaga reply) or static factory methods.
clone()
method, but you don’t know the type of the object at compile time, then you have problem. Java has an interface called Cloneable
. In practice, we should implement this interface if we want to make an object Cloneable
. Object.clone
is protected, so we must override it with a public method in order for it to be accessible.clone()
method of all member object variables also does deep copy, this is too risky of an assumption. You must control the code in all classes.For example org.apache.commons.lang.SerializationUtils will have method for Deep clone using serialization(Source). If we need to clone Bean then there are couple of utility methods in org.apache.commons.beanutils (Source).
cloneBean
will Clone a bean based on the available property getters and setters, even if the bean class itself does not implement Cloneable.copyProperties
will Copy property values from the origin bean to the destination bean for all cases where the property names are the same.In the package import org.apache.commons.lang.SerializationUtils;
there is a method:
SerializationUtils.clone(Object);
Example:
this.myObjectCloned = SerializationUtils.clone(this.object);
This works too. Assuming model
class UserAccount{
public int id;
public String name;
}
First add
compile 'com.google.code.gson:gson:2.8.1'
to your app>gradle & sync. Then
Gson gson = new Gson();
updateUser = gson.fromJson(gson.toJson(mUser),UserAccount.class);
You can exclude using a field by using transient
keyword after access modifier.
Note: This is bad practice. Also don't recommend to use Cloneable
or JavaSerialization
It's slow and broken. Write copy constructor for best performance ref.
Something like
class UserAccount{
public int id;
public String name;
//empty constructor
public UserAccount(){}
//parameterize constructor
public UserAccount(int id, String name) {
this.id = id;
this.name = name;
}
//copy constructor
public UserAccount(UserAccount in){
this(in.id,in.name);
}
}
Test stats of 90000 iteration:
Line UserAccount clone = gson.fromJson(gson.toJson(aO), UserAccount.class);
takes 808ms
Line UserAccount clone = new UserAccount(aO);
takes less than 1ms
Conclusion: Use gson if your boss is crazy and you prefer speed. Use second copy constructor if you prefer quality.
You can also use copy constructor code generator plugin in Android Studio.
Pass the object that you want to copy and get the object you want:
private Object copyObject(Object objSource) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(objSource);
oos.flush();
oos.close();
bos.close();
byte[] byteData = bos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(byteData);
try {
objDest = new ObjectInputStream(bais).readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
return objDest;
}
Now parse the objDest
to desired object.
Happy Coding!
You can deep copy automatically with XStream, from http://x-stream.github.io/:
XStream is a simple library to serialize objects to XML and back again.
Add it to your project (if using maven)
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.3.1</version>
</dependency>
Then
DummyBean dum = new DummyBean();
dum.setDummy("foo");
DummyBean dumCopy = (DummyBean) XSTREAM.fromXML(XSTREAM.toXML(dum));
With this you have a copy without the need to implement any cloning interface.
Here's a decent explanation of clone()
if you end up needing it...
You can try to implement Cloneable
and use the clone()
method; however, if you use the clone method you should - by standard - ALWAYS override Object
's public Object clone()
method.
Yes, you are just making a reference to the object. You can clone the object if it implements Cloneable
.
Check out this wiki article about copying objects.
Other than explicitly copying, another approach is to make the object immutable (no set
or other mutator methods). In this way the question never arises. Immutability becomes more difficult with larger objects, but that other side of that is that it pushes you in the direction of splitting into coherent small objects and composites.
Use a deep cloning utility:
SomeObjectType copy = new Cloner().deepClone(someObject);
This will deep copy any java object, check it out at https://github.com/kostaskougios/cloning
Alternative to egaga's constructor method of copy. You probably already have a POJO, so just add another method copy()
which returns a copy of the initialized object.
class DummyBean {
private String dummyStr;
private int dummyInt;
public DummyBean(String dummyStr, int dummyInt) {
this.dummyStr = dummyStr;
this.dummyInt = dummyInt;
}
public DummyBean copy() {
return new DummyBean(dummyStr, dummyInt);
}
//... Getters & Setters
}
If you already have a DummyBean
and want a copy:
DummyBean bean1 = new DummyBean("peet", 2);
DummyBean bean2 = bean1.copy(); // <-- Create copy of bean1
System.out.println("bean1: " + bean1.getDummyStr() + " " + bean1.getDummyInt());
System.out.println("bean2: " + bean2.getDummyStr() + " " + bean2.getDummyInt());
//Change bean1
bean1.setDummyStr("koos");
bean1.setDummyInt(88);
System.out.println("bean1: " + bean1.getDummyStr() + " " + bean1.getDummyInt());
System.out.println("bean2: " + bean2.getDummyStr() + " " + bean2.getDummyInt());
Output:
bean1: peet 2 bean2: peet 2 bean1: koos 88 bean2: peet 2
But both works well, it is ultimately up to you...
Why is there no answer for using Reflection API?
private static Object cloneObject(Object obj){
try{
Object clone = obj.getClass().newInstance();
for (Field field : obj.getClass().getDeclaredFields()) {
field.setAccessible(true);
field.set(clone, field.get(obj));
}
return clone;
}catch(Exception e){
return null;
}
}
It's really simple.
EDIT: Include child object via recursion
private static Object cloneObject(Object obj){
try{
Object clone = obj.getClass().newInstance();
for (Field field : obj.getClass().getDeclaredFields()) {
field.setAccessible(true);
if(field.get(obj) == null || Modifier.isFinal(field.getModifiers())){
continue;
}
if(field.getType().isPrimitive() || field.getType().equals(String.class)
|| field.getType().getSuperclass().equals(Number.class)
|| field.getType().equals(Boolean.class)){
field.set(clone, field.get(obj));
}else{
Object childObj = field.get(obj);
if(childObj == obj){
field.set(clone, clone);
}else{
field.set(clone, cloneObject(field.get(obj)));
}
}
}
return clone;
}catch(Exception e){
return null;
}
}
Source: Stackoverflow.com