8

I have a class that gets in its constructor a list of objects, List<Object>. Each time the list could be made out of elements from a different type. It's something generic, and I don't know what their class type will be.

I want to save my self a copy of that list, before letting the user change its values. But since the copy is done by reference, both lists (original and copy) are being changed...

How can I copy my list by value?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Dvora
  • 1,175
  • 1
  • 16
  • 26
  • Take a look http://stackoverflow.com/questions/869033/how-do-i-copy-an-object-in-java – DonCallisto May 08 '12 at 09:20
  • Do you mean that your new list should not change if items are added/removed in the original list? Or do you also want to make sure that items in your list can't be modified? – assylias May 08 '12 at 09:26
  • Why copy anything? I've been programming Java for 25 years and never copied a list. Rethink. – user207421 May 15 '22 at 10:10

6 Answers6

2

Your question is not clear.

  • If you want a shallow copy (i.e. a copy of the list that will contain references to the objects in the original list, then the clone method will do the job, as will a copy constructor on a List implementation class.

  • If you want a deep copy (i.e. a copy of the list containing copies of the original objects) then your best bet is to create a new list and populate it with clones of the original list elements. However, there is a catch. The clone method is not provided by default. A lot of common utility classes are cloneable, by custom classes are not ... unless you've implemented it. If your list contains any non-cloneable object, you will get exceptions at runtime.

There are other deep-copying alternatives to clone, but just like cloning they don't work with all classes. And really, that's the crux of the problem if your solution has to be generic.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
1

You need to create a new List and then add a clone of each element of the original list to it.

List<Object> copy = new ArrayList<Object>(inputList.size());
for (Object item : inputList) {
   copy.add(item.clone());
}

Obviously, you need to check that the objects in your list are Cloneable otherwise they won't be copied correctly.

dogbane
  • 266,786
  • 75
  • 396
  • 414
0

Iterate through the passed list and crone its content to create a new List which can then be used without altering the original List.

private List<Object> clone;
public Foo(List<Object> original)
{
  this.clone = new ArrayList<Object>(list.size());
  for(Object item: original)
  { 
   clone.add(item.clone());
  }
}
Bitmap
  • 12,402
  • 16
  • 64
  • 91
0

If your object don’t contain any other reference of other object, you can use Object.clone(), but if not so, you need to make a deep clone.

linuxlsx
  • 138
  • 10
0

In these types of situations, there are three common solutions:

(1) If you know that the individual elements have clone() methods that work as you intend, create a new array and fill it with the clone() of each corresponding element. As a rule of thumb, "basic" objects from JDK such as Strings, number representations etc should be fine. A disadvantage of clone() is that it's a bit of a 'loose cannon': you don't know a priori exactly how deep the 'clone' will be if the method has been overridden for a particular class and what references might potentially get re-used or not. It also has a particular danger that subclasses of cloneable objects which rely on logic in their constructor are liable not to work. But as I say, simple JDK objects should be fine.

(2) Serialise the list to an ObjectOutputStream wrapped around a ByteArrayOutputStream. Then take the resulting byte array, and wrap a ByteArrayInputStream and ObjectInputStream around it and read in from it a new, deep copy of the list.

(3) In an ideal world, create a new list, filling it with explicitly created "copies" of the objects in question. Where it's not too cumbersome to code, this is the ideal solution because you 'know what's actually going on': there'll be no hidden surprises in terms of objects accidentally re-referenced rather than re-created because e.g. a clone() method didn't work as you expected.

As you have a simple container object (an array list) whose structure you can easily re-create, then (2) may be overkill. It can be handy for re-creating more complex structures.

Re (1), you should be particularly suspicious of cloning objects from third party libraries where the objects weren't specifically designed with clone() in mind. The problem is that it's easy for people to either subclass a JDK (cloneable) class or else a token clone() method without actually thinking about it in detail-- in my experience, clone() has some subtleties that many developers aren't aware of (e.g. that the constructor doesn't get called on the new object) which can lead to unanticipated problems. So if you can't actually see reliable source code to be sure that clone() will be safe, I would avoid it.

Neil Coffey
  • 21,615
  • 7
  • 62
  • 83