Вопрос

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

Это было полезно?

Решение

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

Другие советы

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

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

ArrayList backup = new ArrayList();
for (Object obj : data)
   backup.add(obj.clone());

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

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

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

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

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 () также вернет " новый 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
}

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

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. Это означало бы, среди прочего, что-то вроде выполнения clone () для элементов списка, но не для ArrayList (потому что это создаст новый клонированный список с копиями ссылок на те же объекты).

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

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

Вот полностью функционирующий резервный класс 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]
    }
}

Я еще не пробовал, но я думаю, что 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);
}

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top