How do you make a deep copy of an object?
Asked Answered
A

23

366

It's a bit difficult to implement a deep object copy function. What steps you take to ensure the original object and the cloned one share no reference?

Avalon answered 15/9, 2008 at 15:39 Comment(3)
Kryo has built-in support for copying/cloning. This is direct copying from object to object, not object->bytes->object.Sectarianism
Here's a related question that was asked later: Deep clone utility recomendationEssieessinger
Using cloning library saved the day for me! github.com/kostaskougios/cloningShanney
M
191

A safe way is to serialize the object, then deserialize. This ensures everything is a brand new reference.

Here's an article about how to do this efficiently.

Caveats: It's possible for classes to override serialization such that new instances are not created, e.g. for singletons. Also this of course doesn't work if your classes aren't Serializable.

Macfadyn answered 15/9, 2008 at 15:42 Comment(5)
Be aware that the FastByteArrayOutputStream implementation provided in the article could be more efficient. It uses an ArrayList-style expansion when the buffer fills up, but it's better to use a LinkedList-style expansion approach. Instead of creating a new 2x buffer and memcpy-ing the current buffer over, maintain a linked list of buffers, adding a new one when the current fills up. If you get a request to write more data than would fit in your default buffer size, create a buffer node that is exactly as large as the request; the nodes don't need to be the same size.Viki
Just use kryo: github.com/EsotericSoftware/kryo#copyingcloning benchmark slideshare.net/AlexTumanoff/serialization-and-performanceChanel
A good article, which explains the deep copy through serialization : javaworld.com/article/2077578/learn-java/…Ciscaucasia
@BrianHarris linked list is not more efficient than dynamic array. Inserting elements into a dynamic array is amortized constant complexity, while inserting into a linked list is linear complexityTheseus
How much serialize&deserialize slower than copy constructor approach?Pubes
W
82

A few people have mentioned using or overriding Object.clone(). Don't do it. Object.clone() has some major problems, and its use is discouraged in most cases. Please see Item 11, from "Effective Java" by Joshua Bloch for a complete answer. I believe you can safely use Object.clone() on primitive type arrays, but apart from that you need to be judicious about properly using and overriding clone.

The schemes that rely on serialization (XML or otherwise) are kludgy.

There is no easy answer here. If you want to deep copy an object you will have to traverse the object graph and copy each child object explicitly via the object's copy constructor or a static factory method that in turn deep copies the child object. Immutables (e.g. Strings) do not need to be copied. As an aside, you should favor immutability for this reason.

Workman answered 9/12, 2008 at 22:38 Comment(2)
Why is use of Object.clone() discouraged? Please add at least a short explanation to the answer, I don't want to buy the book.Loidaloin
This video mentions a couple of downsides for using clone method youtube.com/watch?v=lcbHHXAONqgCitronellal
G
63

You can make a deep copy with serialization without creating files.

Your object you wish to deep copy will need to implement serializable. If the class isn't final or can't be modified, extend the class and implement serializable.

Convert your class to a stream of bytes:

ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(object);
oos.flush();
oos.close();
bos.close();
byte[] byteData = bos.toByteArray();

Restore your class from a stream of bytes:

ByteArrayInputStream bais = new ByteArrayInputStream(byteData);
Object object = new ObjectInputStream(bais).readObject();
Geraldgeralda answered 29/9, 2011 at 11:17 Comment(6)
If the class is final how would you extend it?Bowens
@KumarManish class MyContainer implements Serializable { MyFinalClass instance; ... }Conway
I find this a great reply. Clone is a messPeanut
@MatteoT. how non-serializable class property will be serialized, non-serializable instance in this case?Gordie
ObjectOutputStream.writeObject() is super slow for big objects, unfortunatelyDevelopment
2022 This apparently doesn't work anymore. Gives a 'java.io.NotSerializableException:'Internode
C
49

You can do a serialization-based deep clone using org.apache.commons.lang3.SerializationUtils.clone(T) in Apache Commons Lang, but be careful—the performance is abysmal.

In general, it is best practice to write your own clone methods for each class of an object in the object graph needing cloning.

Crinoid answered 15/9, 2008 at 16:48 Comment(1)
It's also available in org.apache.commons.lang.SerializationUtilsAngelikaangelina
S
31

One way to implement deep copy is to add copy constructors to each associated class. A copy constructor takes an instance of 'this' as its single argument and copies all the values from it. Quite some work, but pretty straightforward and safe.

EDIT: note that you don't need to use accessor methods to read fields. You can access all fields directly because the source instance is always of the same type as the instance with the copy constructor. Obvious but might be overlooked.

Example:

public class Order {

    private long number;

    public Order() {
    }

    /**
     * Copy constructor
     */
    public Order(Order source) {
        number = source.number;
    }
}


public class Customer {

    private String name;
    private List<Order> orders = new ArrayList<Order>();

    public Customer() {
    }

    /**
     * Copy constructor
     */
    public Customer(Customer source) {
        name = source.name;
        for (Order sourceOrder : source.orders) {
            orders.add(new Order(sourceOrder));
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Edit: Note that copy constructors don't take inheritance into account. For example: If you pass an OnlineOrder (a subclass of Order) to a copy constructor a regular Order instance will be created in the copy, unless you solve this explicitly. You could use reflection to look up a copy constructor in the runtime type of the argument. But I would suggest to not go this route and look for another solution if inheritance needs to be covered in a general way.

Speedometer answered 29/9, 2011 at 11:57 Comment(5)
Just interested in the case that what you are copying is a subclass, but is being referenced by the parent. Is it possible to override the copy constructor?Tetragrammaton
Why does your parent class refer to its subclass? Can you give an example?Speedometer
public class Car extends Vehicle And then referring to the car as a vehicle. originaList = new ArrayList<Vehicle>; copyList = new ArrayList<Vehicle>; originalList.add(new Car()); for(Vehicle vehicle: vehicleList){ copyList.add(new Vehicle(vehicle)); }Tetragrammaton
@AdriaanKoster: If the original list contains a Toyota, your code will put a Car in the destination list. Proper cloning generally requires that the class provide a virtual factory method whose contract states that it will return a new object of its own class; the copy contructor itself should be protected to ensure that it will only be used to construct objects whose precise type matches that of the object being copied).Unseen
So if I understand your suggestion correctly the factory method would call the private copy constructor? How would the copy constructor of a subclass make sure the superclass fields are initialized? Can you give an example?Speedometer
S
25

You can use a library that has a simple API, and performs relatively fast cloning with reflection (should be faster than serialization methods).

Cloner cloner = new Cloner();

MyClass clone = cloner.deepClone(o);
// clone is a deep-clone of o
Stephainestephan answered 20/3, 2014 at 22:52 Comment(0)
B
21

For Spring Framework users. Using class org.springframework.util.SerializationUtils:

@SuppressWarnings("unchecked")
public static <T extends Serializable> T clone(T object) {
     return (T) SerializationUtils.deserialize(SerializationUtils.serialize(object));
}
Beattie answered 19/7, 2017 at 22:15 Comment(2)
This solution works and does not require the use of an external libraryKliber
Same as another answer: This only works for the object that implements Serializable and also for all the fields in it implements Serializable though.Ceporah
B
20

Apache commons offers a fast way to deep clone an object.

My_Object object2= org.apache.commons.lang.SerializationUtils.clone(object1);
Bocock answered 28/1, 2015 at 14:53 Comment(1)
This only works for the object that implements Serializable and also for all the fields in it implements Serializable though.Dallapiccola
M
13

For complicated objects and when performance is not significant i use a json library, like gson to serialize the object to json text, then deserialize the text to get new object.

gson which based on reflection will works in most cases, except that transient fields will not be copied and objects with circular reference with cause StackOverflowError.

public static <T> T copy(T anObject, Class<T> classInfo) {
    Gson gson = new GsonBuilder().create();
    String text = gson.toJson(anObject);
    T newObject = gson.fromJson(text, classInfo);
    return newObject;
}
public static void main(String[] args) {
    String originalObject = "hello";
    String copiedObject = copy(originalObject, String.class);
}
Meant answered 29/11, 2016 at 7:24 Comment(2)
Please adhere to the Java naming conventions for your own and our sake.Hanover
It actually works and also it doesnt enforce developer to implement a Serializable interface.Saransk
M
10

XStream is really useful in such instances. Here is a simple code to do cloning

private static final XStream XSTREAM = new XStream();
...

Object newObject = XSTREAM.fromXML(XSTREAM.toXML(obj));
Mirtamirth answered 23/10, 2008 at 8:3 Comment(2)
Nooo, you do not need the overhead of xml-ing the object.Lafave
@egeleve You do realize that you are replying to a comment from '08 right? I don't use Java any more and there are probably better tools now. However at that time, serializing to a different format and then serializing back seemed like a good hack - it was definitely inefficient.Mirtamirth
E
10

One very easy and simple approach is to use Jackson JSON to serialize complex Java Object to JSON and read it back.

From https://github.com/FasterXML/jackson-databind/#5-minute-tutorial-streaming-parser-generator :

JsonFactory f = mapper.getFactory(); // may alternatively construct directly too

// First: write simple JSON output
File jsonFile = new File("test.json");
JsonGenerator g = f.createGenerator(jsonFile);
// write JSON: { "message" : "Hello world!" }
g.writeStartObject();
g.writeStringField("message", "Hello world!");
g.writeEndObject();
g.close();

// Second: read file back
JsonParser p = f.createParser(jsonFile);

JsonToken t = p.nextToken(); // Should be JsonToken.START_OBJECT
t = p.nextToken(); // JsonToken.FIELD_NAME
if ((t != JsonToken.FIELD_NAME) || !"message".equals(p.getCurrentName())) {
   // handle error
}
t = p.nextToken();
if (t != JsonToken.VALUE_STRING) {
   // similarly
}
String msg = p.getText();
System.out.printf("My message to you is: %s!\n", msg);
p.close();
Entrechat answered 7/2, 2012 at 3:51 Comment(0)
S
8

Use XStream(http://x-stream.github.io/). You can even control which properties you can ignore through annotations or explicitly specifying the property name to XStream class. Moreover you do not need to implement clonable interface.

Strage answered 16/9, 2008 at 5:8 Comment(0)
G
6

Deep copying can only be done with each class's consent. If you have control over the class hierarchy then you can implement the clonable interface and implement the Clone method. Otherwise doing a deep copy is impossible to do safely because the object may also be sharing non-data resources (e.g. database connections). In general however deep copying is considered bad practice in the Java environment and should be avoided via the appropriate design practices.

Gemination answered 15/9, 2008 at 15:44 Comment(1)
Could you describe the "appropriate design practices"?Blowtube
B
6
import com.thoughtworks.xstream.XStream;

public class deepCopy {
    private static  XStream xstream = new XStream();

    //serialize with Xstream them deserialize ...
    public static Object deepCopy(Object obj){
        return xstream.fromXML(xstream.toXML(obj));
    }
}
Benghazi answered 15/9, 2011 at 13:55 Comment(0)
U
6

Using Jackson to serialize and deserialize the object. This implementation does not require the object to implement the Serializable class.

  <T> T clone(T object, Class<T> clazzType) throws IOException {

    final ObjectMapper objMapper = new ObjectMapper();
    String jsonStr= objMapper.writeValueAsString(object);

    return objMapper.readValue(jsonStr, clazzType);

  }
Unadvised answered 21/11, 2019 at 4:43 Comment(0)
O
4

I used Dozer for cloning java objects and it's great at that , Kryo library is another great alternative.

Overbuild answered 17/10, 2014 at 2:8 Comment(1)
Can you elaborate with a code example how to perform the task with dozer?Gradygrae
E
2

BeanUtils does a really good job deep cloning beans.

BeanUtils.cloneBean(obj);
Enneastyle answered 16/2, 2016 at 10:24 Comment(1)
It does shallow cloning.Vanguard
P
1

1)

public static Object deepClone(Object object) {
   try {
     ByteArrayOutputStream baos = new ByteArrayOutputStream();
     ObjectOutputStream oos = new ObjectOutputStream(baos);
     oos.writeObject(object);
     ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
     ObjectInputStream ois = new ObjectInputStream(bais);
     return ois.readObject();
   }
   catch (Exception e) {
     e.printStackTrace();
     return null;
   }
 }

2)

    // (1) create a MyPerson object named Al
    MyAddress address = new MyAddress("Vishrantwadi ", "Pune", "India");
    MyPerson al = new MyPerson("Al", "Arun", address);

    // (2) make a deep clone of Al
    MyPerson neighbor = (MyPerson)deepClone(al);

Here your MyPerson and MyAddress class must implement serilazable interface

Perfidious answered 11/11, 2016 at 14:51 Comment(1)
2022 Not working anymore. Gives a 'NotSerializableException'Internode
C
1

Here is a generic deep cloning method using object serialization and deserialization with byte array streams (to avoid writing to a file).

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

@SuppressWarnings("unchecked")
public static <T extends Serializable> T deepClone(T t) {
    try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);) {
        oos.writeObject(t);
        byte[] bytes = baos.toByteArray();
        try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes))) {
            return (T) ois.readObject();
        }
    } catch (IOException | ClassNotFoundException e) {
        throw new RuntimeException(e);
    }
}
Cockaleekie answered 5/1, 2021 at 18:58 Comment(0)
S
0

Here is an easy example on how to deep clone any object: Implement serializable first

public class CSVTable implements Serializable{
    Table<Integer, Integer, String> table; 
    public CSVTable() {
        this.table = HashBasedTable.create();
    }
    
    public CSVTable deepClone() {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(this);

            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            return (CSVTable) ois.readObject();
        } catch (IOException e) {
            return null;
        } catch (ClassNotFoundException e) {
            return null;
        }
    }

}

And then

CSVTable table = new CSVTable();
CSVTable tempTable = table.deepClone();

is how you get the clone.

Sebiferous answered 28/8, 2020 at 20:0 Comment(0)
C
0

A very quick and simple one-liner solution could be to use Jackson.

Have a look at the example snippet :

ObjectMapper objectMapper = new ObjectMapper();

MyClass deepCopyObject = objectMapper
  .readValue(objectMapper.writeValueAsString(originalObject), MyClass.class);

In the above example : "MyClass" refers to the class of the object you want to be copied .

Christoforo answered 4/4, 2022 at 10:2 Comment(0)
D
0

I am surprised people are not mentioning this, but sometimes mapstruct can be used for these purposes. For instance, in out code we often have smth like that:

@Mapping(target = "status", constant = "DRAFT")
@Mapping(target = "versionNumber", constant = "1")
Contract create(Contract contract);

And mapstruct is intelligent enough to create a brand new copy with values from the old object, maybe with some modifications like in this case above.

I agree that this is not ideal and there are cases when it does not work. But in an overwhelming amount of cases, it really helps. So check it out.

Divider answered 27/10, 2023 at 13:45 Comment(0)
T
0
  1. A clone() example used in a maven package.

https://github.com/3breadt/dd-plist/blob/v1.28.0/src/main/java/com/dd/plist/NSDictionary.java#L323

public class NSDictionary extends NSObject implements Map<String, NSObject> {

    @Override
    public NSDictionary clone() {
        NSDictionary clone = new NSDictionary();
        for (Entry<String, NSObject> entry : this.dict.entrySet()) {
            clone.dict.put(entry.getKey(), entry.getValue() != null ? entry.getValue().clone() : null);
        }

        return clone;
    }
}

https://github.com/3breadt/dd-plist/blob/v1.28.0/src/main/java/com/dd/plist/NSObject.java#L81

public abstract class NSObject implements Cloneable, Comparable<NSObject> {

    /**
     * Creates and returns a deep copy of this instance.
     * @return A clone of this instance.
     */
    @Override
    public abstract NSObject clone();
}
  1. Others talks in https://www.baeldung.com/java-deep-copy
  • Shallow Copy: only copy values of fields
  • Deep Copy: each mutable object in the object graph is recursively copied
    • Copy Constructor
    • clone(): based on the clone method inherited from Object.
  • External Libraries
    • Apache Commons Lang has SerializationUtils#clone
    • JSON Serialization With Gson
    • JSON Serialization With Jackson
  • Sample code
Tessera answered 18/3 at 16:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.