tags:

views:

6394

answers:

9

I have some data stored as ArrayList. And when I want to backup this data,java bounds two objects forever. Which means when I change values in data ArrayList this changes come to backup. I tried to copy values from data separately to backup in the loop, tried to use method data.clone() — nothing helps.

A: 

You could write an object that wraps two ArrayLists. Anything write it so that it adds, removes, and modifies data in both at the same time.

Grant Limberg
+1  A: 

It sounds (if I interpret your question properly; it's a little tough) like you're not copying the data that you're referring to in your ArrayList to your backup; you're copying the reference.

It's hard to say exactly how to solve your problem without knowing what your data type is that you're storing / backing up, but just be sure that you're copying the elements of the data contained within the ArrayList. That would mean, among other things, to do things like perform a clone() on the elements of the list, but not on the ArrayList (because that'll create a new cloned list with copies of the references to the same objects).

McWafflestix
+2  A: 

All of these processes make shallow copies. If you're changing properties of objects with in the array, the two arrays have references to the same instance.

List org = new java.util.ArrayList();
org.add(instance)
org.get(0).setValue("org val");
List copy = new java.util.ArrayList(org);
org.get(0).setValue("new val");

copy.get(0).getValue() will return "new val" as well because org.get(0) and copy.get(0) return the exact same instance. You have to perform a deep copy like so:

List copy = new java.util.ArrayList();
for(Instance obj : org) {
    copy.add(new Instance(obj)); // call to copy constructor
}
sblundy
Thanks! I had the same Question as the OP, and you answered it perfectly. DeepCopy vs Shallow Copy! and more importantly how to actually do a deep copy!
Mark Underwood
+7  A: 

Your question isn't very clear. If you clone() an ArrayList, the clone will not be modified if you change the contents of the original (ie if you add or remove elements) but it's a "shallow copy" so if you change the actual objects in the original they will also be changed in the clone.

If you want to make a "deep copy", so that changes to the actual objects will not affect the backups of them in the clone, then you need to create a new ArrayList and then go through the original one and for each element, clone it into the new one. As in

ArrayList backup = new ArrayList();
for (Object obj : data)
   backup.add(obj.clone());
Paul Tomblin
+6  A: 

I'm assuming data is the name of the ArrayList you wanted to backup. If so, you should know that clone is not deep - it only creates a copy of the object on which it is invoked, which in this case is the list. If it were a deep clone, it would fill the new list with clones of the objects in it.

Since it's not deep, if you change the objects the list contains, then the backup list will show those changes as well, since it's containing the same objects. The only time you'll not see changes in the backup after changing the "current" list is when you add or remove objects from the current list.

Some classes may override clone to be deep, but not all. In general, it's not something you can rely on. When creating a backup copy of Java collections, remember to either clone the contained objects as well, or deal only with collections of immutable objects.

Paul Brinkley
+7  A: 

I think you need to .clone() the individual objects. Cloning the ArrayList is not "deep"; it will only clone the references to the object.

divideandconquer.se
A: 

Regarding the cloning problem, once I solved this by serializing the entire collection into a string then serializing it back out into a new object. This forces you to make all your objects serializable and take when two objects really want to reference a single third object, but it can be a pretty good balance of simplicity and usefulness.

Actually, I haven't tried this but you could probably use a pipe to serialize in and out at the same exact time so that you aren't storing 3 copies in memory (if it's a huge collection)

Bill K
A: 

I haven't tried it yet, but I think Collections.copy will do that.

[EDIT] Now, I tried:

static String GetRandomString(int length)
{
  UUID uuid = UUID.randomUUID();
  return uuid.toString().substring(0, length);  
}

public static void main(String[] args)
{
  ArrayList<String> al = new ArrayList<String>(20);
  for (int i = 0; i < 10; i++)
  {
    al.add(GetRandomString(7));
  }
  ArrayList<String> cloneArray = new ArrayList<String>(al);
  Collections.copy(cloneArray, al);
  System.out.println(al);
  System.out.println(cloneArray);
  for (int i = 9; i >= 0; i -= 2)
  {
    al.remove(i);
  }
  System.out.println(al);
  System.out.println(cloneArray);
}
PhiLho
This I believe dont actually show the deep copy since the add/remove operation wont alter the original list.I tried your same code but replaced the list content with a custom class and altered the content (rather than removing them), then the copied list was also altered.
Nrj
@Nrj: ah, you are right, the lists are independent but still point to (reference) the same objects, so it is still a shallow copy. My bad (hey, two years ago, I wasn't very good at Java! :-))
PhiLho
A: 

Depends what you need. Shallow copy (items in list are references to the same as in the original):

ArrayList backup = new ArrayList(mylist.size());
backup.addAll(mylist);

Deep copy (items are copies also):

ArrayList backup = new ArrayList(mylist.size());
for(Object o : mylist) {
    backup.add(o.clone());
}
Tore A.