我有一些数据存储为ArrayList
. 而当我想备份这些数据时,java 会永远绑定两个对象。这意味着当我更改数据中的值时,ArrayList
这些更改就会备份。我尝试将数据中的值分别复制到循环中的备份,尝试使用方法data.clone()
- 没有任何帮助。
10 回答
你的问题不是很清楚。如果您 clone() 一个 ArrayList,如果您更改原始内容(即添加或删除元素),克隆将不会被修改,但它是“浅拷贝”,因此如果您更改原始对象中的实际对象,它们将也可以在克隆中进行更改。
如果要进行“深拷贝”,以便对实际对象的更改不会影响它们在克隆中的备份,那么您需要创建一个新的 ArrayList 然后遍历原始的,并且对于每个元素,克隆它进入新的。如在
ArrayList backup = new ArrayList();
for (Object obj : data)
backup.add(obj.clone());
我认为您需要.clone()
单个对象。克隆ArrayList
并不“深”;它只会克隆对对象的引用。
我假设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()
也会返回"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
}
取决于你需要什么。浅拷贝(列表中的项目与原始项目相同):
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 会这样做。
[编辑] 现在,我尝试了:
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);
}
您可以编写一个包含两个 ArrayList 的对象。任何东西都写它,以便它同时添加、删除和修改两者中的数据。