31

Possible Duplicate:
Java: how to clone ArrayList but also clone its items?

I have a sample program like the following:

ArrayList<Invoice> orginalInvoice = new ArrayList<Invoice>();

//add some items into it here

ArrayList<Invoice> copiedInvoice = new ArrayList<Invoice>();

copiedInvoice.addAll(orginalInvoice);


I thought I can modify items inside the copiedInvoice and it will not affect these items inside originalInoice. But I was wrong.

How can I make a separated copy / clone of an ArrayList?

Thanks

Community
  • 1
  • 1
5YrsLaterDBA
  • 33,370
  • 43
  • 136
  • 210
  • Possible duplicate : http://stackoverflow.com/questions/715650/java-how-to-clone-arraylist-but-also-clone-its-items as Zed mentionned. – Philippe Carriere Aug 25 '09 at 19:26
  • 1
    I'm closing this as a duplicate, but it shouldn't get deleted. Not everyone is going to know to search using the more technically correct "clone" terminology that the original uses. – Bill the Lizard Aug 25 '09 at 20:34

4 Answers4

42

Yes that's correct - You need to implement clone() (or another suitable mechanism for copying your object, as clone() is considered "broken" by many programmers). Your clone() method should perform a deep copy of all mutable fields within your object. That way, modifications to the cloned object will not affect the original.

In your example code you're creating a second ArrayList and populating it with references to the same objects, which is why changes to the object are visible from both Lists. With the clone approach your code would look like:

List<Foo> originalList = ...;

// Create new List with same capacity as original (for efficiency).
List<Foo> copy = new ArrayList<Foo>(originalList.size());

for (Foo foo: originalList) {
  copy.add((Foo)foo.clone());
}

EDIT: To clarify, the above code is performing a deep copy of the original List whereby the new List contains references to copies of the original objects. This contrasts to calling ArrayList.clone(), which performs a shallow copy of the List. In this context a shallow copy creates a new List instance but containing references to the original objects.

Adamski
  • 54,009
  • 15
  • 113
  • 152
  • I think the answer could be more helpful if you went into the difference between cloning the list vs cloning each object in the list. However, the answer does understand this even though it doesn't explain it, so +1 to compensate for the down vote. – Yishai Aug 25 '09 at 19:11
  • 2
    Error: clone has "protected" access in java.lang.object. – Bilal Rabbani Oct 14 '16 at 14:05
  • The code snippet is based on the assumption that clone() has been overridden in class Foo to be public. – Adamski Oct 17 '16 at 09:51
22

If you are storing mutable objects into the ArrayList, you will need to copy each object when you copy the ArrayList. Otherwise, the new ArrayList will still hold the original references.

However if you're storing immutable objects, it's fine to use:

ArrayList copiedInvoice = new ArrayList(originalInvoice);

Lucky
  • 4,787
  • 9
  • 40
  • 50
3

I thought I can modify items inside the copiedInvoice and it will not affect these itmes inside originalInoice.

This happens because what gets copied is the reference variable and not the object it self.

Hence you end up with two "references" pointing to the same object.

If you need to copy the whole object you may need to clone it.

But you might have problems if you don't clone the object internal attributes if they happen to be other objects.

For instance the following class definition won't give you any problem.

  public class Something {
       private int x;
       private int y;
       private String stringObject;
   }

If you create a copy of that, you would copy the current values of its attributes and that's it.

But if your class do have another object inside you might consider to clone it too.

 class OtherSomething {
        Something something;
       private int x;
 }

If you do the following:

 Something shared = new Something();

 OtherSomething one = new OtherSomething();

 OtherSomething two = new OtherSomething();

 one.something = shared;
 two.something = shared;

In this case, both one and two have the same reference variable to the same shared "something" and changing the value in one would affect the other.

That's why it is much simpler/better/easier to use immutable objects.

If you need to change the value of an immutable object you just create a new one with the correct value.

OscarRyz
  • 196,001
  • 113
  • 385
  • 569
  • You state that you won't have a problem sharing your first class: Something. However, Date is an object and is more importantly is mutable so would need to be copied. – Adamski Aug 25 '09 at 19:24
  • :P Bad pick of immutable object.. I had Date in mind for mutable object. Thank you Adamski – OscarRyz Aug 25 '09 at 19:37
-1

Take a look at ByteArrayOutputStream and ByteArrayInputStream. If all of your classes implement Serializable, then you can make a copy using the above mentioned classes.

Dave
  • 13,518
  • 7
  • 42
  • 51