Как сделать резервную копию ArrayList в Java? - PullRequest
9 голосов
/ 19 ноября 2008

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

Ответы [ 10 ]

15 голосов
/ 19 ноября 2008

Ваш вопрос не очень понятен. Если вы клонируете () ArrayList, клон не будет изменен, если вы измените содержимое оригинала (то есть, если вы добавите или удалите элементы), но это «мелкая копия», поэтому, если вы измените фактические объекты в оригинале, также можно изменить в клоне.

Если вы хотите сделать «глубокую копию», чтобы изменения в реальных объектах не влияли на их резервное копирование в клоне, то вам нужно создать новый ArrayList, а затем просмотреть исходный и для каждого элемент, клонировать его в новый. Как в

ArrayList backup = new ArrayList();
for (Object obj : data)
   backup.add(obj.clone());
12 голосов
/ 19 ноября 2008

Я думаю, вам нужно .clone() отдельные объекты. Клонирование ArrayList не является «глубоким»; он будет клонировать только ссылки на объект.

8 голосов
/ 19 ноября 2008

Я предполагаю, что data - это имя ArrayList, которое вы хотите сделать резервную копию. Если это так, вы должны знать, что clone не deep - он создает только копию объекта, для которого он вызывается, который в данном случае является списком. Если бы это был глубокий клон, он бы заполнил новый список клонами объектов в нем.

Поскольку это не глубоко, если вы измените объекты, содержащиеся в списке, то в списке резервных копий также будут показаны эти изменения, поскольку он содержит те же объекты. Единственный раз, когда вы не увидите изменений в резервной копии после изменения «текущего» списка, это когда вы добавляете или удаляете объекты из текущего списка.

Некоторые классы могут переопределять clone, чтобы быть глубокими, но не все. В общем, это не то, на что вы можете положиться. При создании резервной копии коллекций Java не забудьте либо клонировать содержащиеся объекты, либо иметь дело только с коллекциями неизменяемых объектов.

4 голосов
/ 19 ноября 2008

Все эти процессы делают мелкие копии. Если вы изменяете свойства объектов в массиве, эти два массива имеют ссылки на один и тот же экземпляр.

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
}
3 голосов
/ 20 ноября 2008

Зависит от того, что вам нужно. Мелкая копия (элементы в списке являются ссылками на те же, что и в оригинале):

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

Глубокая копия (элементы также являются копиями):

ArrayList backup = new ArrayList(mylist.size());
for(Object o : mylist) {
    backup.add(o.clone());
}
1 голос
/ 19 ноября 2008

Звучит (если я правильно интерпретирую ваш вопрос; это немного сложно), как будто вы не копируете данные, на которые ссылаетесь в своем ArrayList, в свою резервную копию; Вы копируете ссылку.

Трудно точно сказать, как решить вашу проблему, не зная, какой тип данных вы храните / резервируете, но просто убедитесь, что вы копируете элементы данных, содержащихся в ArrayList. Это означало бы, среди прочего, что-то вроде выполнения clone () для элементов списка, но не для ArrayList (потому что это создаст новый клонированный список с копиями ссылок на те же объекты).

0 голосов
/ 08 апреля 2018

Вот полностью работающий класс резервного копирования ArrayList, который проверяет, существует ли уже ArrayList. По сути, это просто цикл, циклически проходящий по списку и добавляющий их в новый список вручную.

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]
    }
}
0 голосов
/ 20 ноября 2008

Я еще не пробовал, но я думаю, что Collections.copy сделает это.

[ПРАВИТЬ] Теперь я попробовал:

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);
}
0 голосов
/ 20 ноября 2008

Относительно проблемы клонирования, как только я решил это, сериализовав всю коллекцию в строку, затем сериализовав ее обратно в новый объект. Это заставляет вас делать все ваши объекты сериализуемыми и использовать, когда два объекта действительно хотят ссылаться на один третий объект, но это может быть довольно хорошим балансом простоты и полезности.

На самом деле, я не пробовал этого, но вы, вероятно, могли бы использовать канал для сериализации в одно и то же время, чтобы вы не хранили 3 копии в памяти (если это огромная коллекция)

0 голосов
/ 19 ноября 2008

Вы можете написать объект, который оборачивает два ArrayLists. Все, что пишут, добавляет, удаляет и изменяет данные в обоих случаях одновременно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...