tags:

views:

2961

answers:

11

Is there any utility for deep cloning for java collections:

  • Arrays
  • Lists
  • Maps

NOTE: prefer some solution without usage of serialization, but with use of Object.clone() method. I can be sure that my custom object will implement clone() method and will use only java-standard classes that are cloneable...

+1  A: 

I havent used java in a long time but look at this article might solve your problem www.matthicks.com/2008/05/fastest-deep-cloning.html

i think thay use Serialization and reflection..

Petoj
links to source in article is broken..
Andreas Petersson
http://javatechniques.com/blog/faster-deep-copies-of-java-objects/(this is the first link on the page but there is source code!)
Petoj
+5  A: 

One general way to deep-clone an arbitrary collection is to serialize it to a stream, then read it back into a new collection. You'll be rehydrating completely new objects that don't have any relationship to the old ones, other than being identical copies.

Check out Bruno's answer for a link to the Apache Commons serialization utility classes, which will be very helpful if this is the route you decide to take.

John Feminella
Serialization solution is fine, but I thought about something without it. I can garantie that my custom object will be correctly deep-cloned with clone() method, but I want helper that will do it for standard java classes...
Supowski
Serialization way to clone is fine, but I had some fields that are not under my control and that are not serializable...
Supowski
+3  A: 

One possibility is to use serialization:

http://commons.apache.org/lang/apidocs/org/apache/commons/lang/SerializationUtils.html

bruno conde
A: 

Use serialization and then deserialization, but be aware thah this approach works only with Serializable classes without transient fields. Also, your singletons will not be singletons anymore.

Dev er dev
+8  A: 

All approaches to copy objects in Java have serious flaws:

Clone

  1. The clone() method is protected, so you can't call it directly unless the class in question overrides it with a public method.
  2. clone() doesn't call the constructor. Any constructor. It will allocate memory, assign the internal class field (which you can read via getClass()) and copy the fields of the original.

For more issues with clone(), see item 11 of Joshua Bloch's book "Effective Java, Second Edition"

Serialize

Serialize is even worse; it has many of the flaws of clone() and then some. Joshua has a whole chapter with four items for this topic alone.

My Solution

My solution is add a new interface to my projects:

public interface Copyable<T> {
    T copy ();
    T createForCopy ();
    void copyTo (T dest);
}

The code looks like this:

class Demo implements Copyable<Demo> {
    public Demo copy () {
        Demo copy = createForCopy ();
        copyTo (copy);
        return copy;
    }
    public void createForCopy () {
        return new Demo ();
    }
    public void copyTo (Demo dest)
        super.copyTo (dest);
        ...copy fields of Demo here...
    }
}

Unfortunately, I have to copy this code to all my objects but it's always the same code, so I can use an Eclipse editor template. Advantages:

  1. I can decide which constructor to call and how to initialize which field.
  2. Initialization happens in a deterministic order (root class to instance class)
  3. I can reuse existing objects and overwrite them
  4. Type safe
  5. Singletons stay singletons

For standard Java types (like collections, etc), I use a utility class which can copy those. The methods have flags and callbacks, so I can control how deep a copy should be.

Aaron Digulla
I did something similar by implementing clone() in all classes that I need to clone. Biggest problem is that if I have collection I have to iterate over it and copy it by my self...
Supowski
Use a helper function which accepts a Collection and returns an ArrayList: Since you know the size, that will allocate memory just once and ArrayList is fast for the usual kinds of access.
Aaron Digulla
+3  A: 

I think the current green answer is bad , why you might ask?

  • It adds a lot of code
  • It requires you to list all fields to be copied and do this
  • This will not work for Lists when using clone() (This is what clone() for HashMap says: Returns a shallow copy of this HashMap instance: the keys and valuesthemselves are not cloned.) so you end up doing it manually (this makes me cry)

Oh and by the way serialization is also bad, you might have to add Serializable all over the place (this also makes me cry).

So what is the solution:

Java Deep-Cloning library The cloning library is a small, open source (apache licence) java library which deep-clones objects. The objects don't have to implement the Cloneable interface. Effectivelly, this library can clone ANY java objects. It can be used i.e. in cache implementations if you don't want the cached object to be modified or whenever you want to create a deep copy of objects.

Cloner cloner=new Cloner();
cloner.deepClone(someObject);

Check it out at http://robust-it.co.uk/clone/index.php

+1  A: 

Shallow cloning a collection is easy, but if you want to deep clone, a library will probably do you better than hand coding it (since you want to clone the elements inside the collection as well).

I've used the Cloner library just like jliax mentions. Also, I specifically performance tested it against XStream (which can 'clone' by serializing then deserializing) and binary serialization. Though XStream is very fast at serializing to/from xml, Cloner is much faster at cloning:

0.0851 ms : xstream (clone by serializing/deserializing)
0.0223 ms : binary serialization (clone by serializing/deserializing)
0.0017 ms : cloner
* average time to clone a simple object (two fields) and no default, public constructor. Run 10,000 times.

In addition to being fast, here are more reasons to choose cloner:

  1. performs a deep clone of any object (even those you don't write yourself)
  2. you don't have to keep your clone() method up-to-date each time you add a field
  3. you can clone objects that don't have a default public constructor
  4. works with Spring
  5. (optimization) doesn't clone known immutable objects (like Integer, String, etc.)
  6. easy to use. Example:

    cloner.deepClone(anyObject);

Brad Cupit
A: 

Hi all, I am the creator of the cloner lib, the one that Brad presented. This is a solution for cloning objects without having to write any extra code (no need for serializable objects or impl clone() method)

It's quite fast as Brad said, and recently I uploaded a version which is even faster. Note that manually implementing a clone() method will be faster than clone lib, but then again you'll need to write a lot of code.

Cloner lib has worked quite well for me since I am using it in a cache implementation for a site with very heavy traffic (~1 million requests/day). The cache should clone approximately 10 objects per request. It is quite reliable and stable. But please be aware that cloning is not without risk. The lib can be configured to println every class instance that it clones during dev. This way you can check if it clones what you think it should clone - object graphs can be very deep and can contain references to a surprisingly large amount of objects. With clone lib, you can instruct it to not clone the objects that you don't want, i.e. singletons.

Konstantinos Kougios
The library looks fine, will check it some time later...
Supowski
A: 

Theres a good library that does deep clones good for deattach entities from hibernate sessions.

http://sourceforge.net/projects/cloneutils/

Paul
A: 

Previously a reference to my blog: http://www.matthicks.com/2008/05/fastest-deep-cloning.html was referenced but it's an old post and the source link was broken. I've fixed the link for anyone still interested.

Matt Hicks
+1  A: 

There is yet another deep cloning utility at http://www.genericdeepcopy.com/

Aaron