5

I am trying to clone an object of MyGraph and I want it to be a deep copy so the arraylists inside the object are also cloned. Right now I have:

public static MyGraph deepCopy(MyGraph G){
    MyGraph Copy = (MyGraph) G.clone();

    Copy.VertexG = (ArrayList<Integer>) G.VertexG.clone();
    Copy.EdgeG = (ArrayList<String>) G.EdgeG.clone();

    return Copy;
}

This returns an error when it tries to clone the arraylist. I am not sure if this is the right way to add the arraylists to the object.

JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
Paul
  • 59
  • 1
  • 1
  • 4
  • 8
    What kind of error? – bsiamionau Mar 01 '13 at 10:10
  • http://stackoverflow.com/questions/715650/how-to-clone-arraylist-and-also-clone-its-contents – CAMOBAP Mar 01 '13 at 10:13
  • @CAMOBAP not correct, he has immutable objects in the list (`Integer`, `String`) – gaborsch Mar 01 '13 at 10:16
  • What does MyGraph.clone() do? – Silver Quettier Mar 01 '13 at 10:18
  • MyGraph.clone() should clone the object MyGraph but I also need to clone the arraylists inside MyGraph. I am getting a null pointer exception from the vertex and edge lines. – Paul Mar 01 '13 at 10:23
  • @SilverQuettier that is, `clone()` is making the shallow copy – gaborsch Mar 01 '13 at 10:27
  • NPE? Sounds to me that the MyGraph you try to clone did not have properly initialized VertexG and EdgeG ArrayLists. You could wrap this in a test for NULL and create a new one if needed. – Silver Quettier Mar 01 '13 at 10:33
  • Doing a quick test it seems that the clone graph 'copy' is null for some reason. Which would explain why it can't add the arraylists. In MyGraph I have this: public Object clone(){ try{ return super.clone(); } catch(CloneNotSupportedException e){ return null; } } Any ideas what I could do? – Paul Mar 01 '13 at 10:38
  • Seems like the call to `super.clone()` throws the `CloneNotSupportedException`. What is the super class of `MyGraph`? Does it implement the `Cloneable` interface? – Modus Tollens Mar 01 '13 at 10:46
  • If you can call `clone()` on an instance of `MyGraph`, it is for sure not `null`. Why would you even consider returning `null` in your clone method? If parent can not clone, you should do it yourself and not just pass `null`... – brimborium Mar 01 '13 at 10:48
  • 1
    @Paul would you show the whole *class definition*, (data definition, clone(), deepCopy() methods). Leave the business methods out. Also show which is the line where your NPE comes from. – gaborsch Mar 01 '13 at 11:12

4 Answers4

3

The clone operation in ArrayList returns a shallow copy of the object, and will not be suitable for your purposes. The manual workaround is to:

  1. Create a target array list of the same size as the source list
  2. Iterate the source list and create a clone of each of it's items, into the target list

Obviously, this will only work if the array list contains items that implement clone, and in addition that the items clone operation actually returns a deep copy. In other words, its not guaranteed. Actually, implementing deep clone functionality for Java objects is not at all easy, refer to extensive discussions in Java: recommended solution for deep cloning/copying an instance and other SO threads to get a feel for the options available. In addition to the answers provided there, here are some other options:

Serialization

If all (the required) objects in your hierarchy can be serialized then you can use this simple code to do a deep clone:

public MyGraph deepCopy() {
    try {
        final ByteArrayOutputStream baos = new ByteArrayOutputStream(256);
        final ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(this);
        oos.close();

        final ObjectInputStream ois = new ObjectInputStream(
                new ByteArrayInputStream(baos.toByteArray()));
        final MyGraph clone = (QuicksortTest) ois.readObject();
        return clone;
    } catch (final Exception e) {
        throw new RuntimeException("Cloning failed");
    }
}

Note that some deep-clone libraries combine standard Java serialization with reflection hacks and/or byte code instrumentation in order to make the entire object hierarchy fully serializable. You may, or may not, need that.

Copy tools

For example, Dozer, provide fast deep-copy functionality. Orika can also achieve the same, albeit with more configuration:

public MyGraph deepCopy() {
    final DozerBeanMapper mapper = new DozerBeanMapper();
    final QuicksortTest clone = mapper.map(this, MyGraph.class);
    return clone;
}

The only downside of course, being the additional dependencies you need to pull into your project.

On a total tangent, your deepCopy method should not be static. Also, you should seriously considering encapsulating the state of your object by making it private and implementing getters/setters.

Community
  • 1
  • 1
Perception
  • 79,279
  • 19
  • 185
  • 195
  • Wrong, he has immutable objects in the `ArrayList`. You are true, that the elements of the `ArrayList` are not cloned, but it is totally indifferent in this case. – gaborsch Mar 01 '13 at 10:41
  • Uh, @GaborSch - who said you cannot clone immutable objects? It *might* present a problem for third party tools, but ***not*** for serialization. – Perception Mar 01 '13 at 10:43
  • AFAIK OP has not asked about serialization. He just simply wants to clone his Graph. Of course, you can have multiple instances of immutable object, and it is also true, that it *may* cause anomalies with serialization. Anyway, nice answer, but **not for this question.** – gaborsch Mar 01 '13 at 10:53
  • Actually, the question is regarding ***deep copying***, not cloning. The standard JDK `clone` is just one possible implementation option (that would not work) for this case. – Perception Mar 01 '13 at 10:55
  • The standard `ArrayList.clone()` **will work** with immutable objects. It does not copy the elements (only the list), but that's enough, since **you cannot mutate a `String`**. – gaborsch Mar 01 '13 at 11:05
  • Which is one of the great things about working with immutable objects. You do not need to clone them. Which is what you are ***trying*** to say. – Perception Mar 01 '13 at 11:17
0

Every class you call clone() on has to implement the Cloneable interface. From your comments, i understand your MyGraph class does not implement the Cloneable interface. In that case, Object.clone() throws the CloneNotSupportedException.

kutschkem
  • 7,826
  • 3
  • 21
  • 56
0

Trying to do deep copy with cloning is complicated as you need to ensure that all classes implement Cloneable interface and they have clone() definition.

Better way would be to do it through Copy Constructor or Serialization. Here is my blog on which i have discussed it in detail. hope it helps :)

rai.skumar
  • 10,309
  • 6
  • 39
  • 55
0

A fundamental conceptual problem with cloning in Java [arguably the fundamental problem] is it's possible for a field of a type like List<String> to represent at least five very different things:

  • The only extant reference to a mutable list, which is used to encapsulate the mutable state thereof, but which--being the only extant reference--would not encapsulate its identity (the list could be replaced with a different list holding the same items, without altering the program's semantics). A correct clone of the object that contains this field would hold a reference to a different list holding the same items.

  • A reference to a mutable list which, while it would allow itself to be mutated, will never be exposed to anything that would actually mutate it. This reference may be shared with other code only if that other code will refrain from mutating the list or exposing it to code that might do so. A correct clone of the object that contains this field could hold a reference to either the original list or a different list holding the same items.

  • A reference to an immutable list. This reference may be shared freely with other code without regard for how that code might expose it. As above, the correct clone of the object containing this field could hold a reference to either the original list or a copy.

  • A reference to a mutable list which is owned by some other object, which is held for purpose of binding this to those aspects of the other object's state which are encapsulated in the list. A correct clone of the object holding the field must hold a reference to that same list, and not a copy thereof.

  • A reference to a mutable list which this object owns, but to which other objects also have a reference for purpose of either observing this object's state, or feeding information to this object. The object holding this field cannot be correctly cloned in isolation, though it might be possible to clone a group of inter-connected objects and give the new set of objects a set of interconnections which was isomorphic to those in the original group.

The concrete type of the object to which the field holds a reference may distinguish between some of the above cases, but it cannot distinguish among all of them. In particular, the first and fourth scenarios require different behavior on the part of the cloning method, despite the fact that in both scenarios the reference might likely pointing to an ArrayList<string>.

supercat
  • 77,689
  • 9
  • 166
  • 211