How to make a separated copy of an ArrayList? [dup

2020-02-03 13:04发布

问题:

This question already has answers here:
Closed 10 years ago.

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

回答1:

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.



回答2:

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);



回答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.



回答4:

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.