У меня есть некоторые данные, хранящиеся как ArrayList. И когда я хочу сделать резервную копию этих данных, java навсегда ограничивает два объекта. Это означает, что когда я меняю значения в данных ArrayList, эти изменения попадают в резервную копию. Пробовал копировать значения из данных отдельно в резервную копию в цикле, пробовал использовать метод data.clone() - ничего не помогает.




Вы можете написать объект, охватывающий два списка ArrayList. Все, что угодно, пишите так, чтобы добавлять, удалять и изменять данные в обоих одновременно.
Это звучит (если я правильно интерпретирую ваш вопрос; это немного сложно), как будто вы не копируете данные, на которые вы ссылаетесь в своем ArrayList, в свою резервную копию; вы копируете ссылку.
Трудно точно сказать, как решить вашу проблему, не зная, какой у вас тип данных, который вы храните / копируете, но просто убедитесь, что вы копируете элементы данных, содержащиеся в ArrayList. Это означало бы, среди прочего, делать такие вещи, как выполнение clone () для элементов списка, но не для ArrayList (потому что это создаст новый клонированный список с копиями ссылок на те же объекты).
Все эти процессы создают мелкие копии. Если вы изменяете свойства объектов в массиве, два массива имеют ссылки на один и тот же экземпляр.
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() также вернет "new val", потому что org.get(0) и copy.get(0) возвращают один и тот же экземпляр. Вы должны выполнить глубокую копию следующим образом:
List copy = new java.util.ArrayList();
for(Instance obj : org) {
copy.add(new Instance(obj)); // call to copy constructor
}
Спасибо! У меня был тот же вопрос, что и у OP, и вы на него отлично ответили. DeepCopy против Shallow Copy! и, что более важно, как на самом деле сделать глубокую копию!
Ваш вопрос не очень ясен. Если вы clone () ArrayList, клон не будет изменен, если вы измените содержимое оригинала (то есть, если вы добавите или удалите элементы), но это «неглубокая копия», поэтому, если вы измените фактические объекты в оригинале, они будут также можно изменить в клоне.
Если вы хотите сделать «глубокую копию», чтобы изменения фактических объектов не повлияли на их резервные копии в клоне, вам необходимо создать новый список ArrayList, а затем просмотреть исходный и для каждого элемента клонировать это в новый. Как в
ArrayList backup = new ArrayList();
for (Object obj : data)
backup.add(obj.clone());
Я предполагаю, что data - это имя ArrayList, для которого вы хотите сделать резервную копию. Если это так, вы должны знать, что clone не является глубокий - он только создает копию объекта, для которого он вызывается, который в данном случае является списком. Если бы это был глубокий клон, он бы заполнил новый список клонами объектов в нем.
Поскольку он неглубокий, если вы измените объекты, содержащиеся в списке, список резервных копий также отобразит эти изменения, поскольку он содержит те же объекты. Единственный случай, когда вы не увидите изменений в резервной копии после изменения «текущего» списка, - это когда вы добавляете или удаляете объекты из текущего списка.
Некоторые классы могут переопределять clone как глубокие, но не все. В общем, на это нельзя положиться. При создании резервной копии коллекций Java не забудьте либо клонировать также содержащиеся объекты, либо иметь дело только с коллекциями неизменяемых объектов.
Думаю, нужно .clone() по отдельным объектам. Клонирование ArrayList не «глубокое»; он только клонирует ссылки на объект.
Что касается проблемы клонирования, как только я решил это, сериализовав всю коллекцию в строку, а затем сериализовав ее обратно в новый объект. Это заставляет вас сделать все ваши объекты сериализуемыми и принимать, когда два объекта действительно хотят ссылаться на один третий объект, но это может быть довольно хорошим балансом простоты и полезности.
На самом деле, я не пробовал этого, но вы, вероятно, могли бы использовать канал для сериализации в одно и то же точное время, чтобы вы не хранили в памяти 3 копии (если это огромная коллекция)
Я еще не пробовал, но думаю, что Collections.copy это сделает.
[EDIT] Теперь я попробовал:
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);
}
Я считаю, что на самом деле это не показывает глубокую копию, поскольку операция добавления / удаления не изменяет исходный список. Я попробовал ваш тот же код, но заменил содержимое списка настраиваемым классом и изменил содержимое (а не удалял его), затем скопированный список также был изменен.
@Nrj: ах, вы правы, списки независимы, но все же указывают (ссылаются) на одни и те же объекты, так что это все еще неглубокая копия. Мой плохой (эй, два года назад я не очень хорошо разбирался в Java! :-))
Зависит от того, что вам нужно. Неглубокая копия (элементы в списке являются ссылками на те же, что и в оригинале):
ArrayList backup = new ArrayList(mylist.size());
backup.addAll(mylist);
Глубокая копия (элементы также являются копиями):
ArrayList backup = new ArrayList(mylist.size());
for(Object o : mylist) {
backup.add(o.clone());
}
Вот полностью работающий класс резервного копирования ArrayList, который проверяет, существует ли уже ArrayList. По сути, это просто цикл for, который просматривает список и вручную добавляет их в новый список.
import java.util.ArrayList;
public class Snapshot {
private ArrayList<Integer> dataBackup;
public Snapshot(ArrayList<Integer> data)
{
dataBackup = new ArrayList<Integer>();
for(int i = 0; i < data.size(); i++)
{
dataBackup.add(data.get(i));
}
}
public ArrayList<Integer> restore()
{
return dataBackup;
}
public static void main(String[] args)
{
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
Snapshot snap = new Snapshot(list);
list.set(0, 3);
list = snap.restore();
System.out.println(list); // Should output [1, 2]
list.add(4);
list = snap.restore();
System.out.println(list); // Should output [1, 2]
}
}
Что вы имеете в виду под «резервным копированием»? Вы имеете в виду, что хотите создать еще один список ArrayList, содержащий то, что находится в текущем списке ArrayList?