質問
ArrayList
として保存されているデータがあります。そして、このデータをバックアップしたいとき、javaは2つのオブジェクトを永久にバインドします。つまり、データ ArrayList
の値を変更すると、この変更がバックアップされます。ループ内のバックアップにデータから値を個別にコピーしようとしました。メソッド data.clone()
を使用しようとしました—何も助けません。
解決
個々のオブジェクトを .clone()
する必要があると思います。 ArrayList
の複製は" deep&quot ;;ではありません。オブジェクトへの参照のみを複製します。
他のヒント
あなたの質問はあまり明確ではありません。 ArrayListをclone()した場合、元のコンテンツを変更しても(つまり、要素を追加または削除しても)クローンは変更されませんが、それは「浅いコピー」です。元のオブジェクトを変更すると、クローンでも変更されます。
「ディープコピー」を作成して、実際のオブジェクトへの変更がクローン内のオブジェクトのバックアップに影響しないようにする場合は、新しいArrayListを作成してから、元の各要素を、新しい要素に複製します。
のようにArrayList backup = new ArrayList();
for (Object obj : data)
backup.add(obj.clone());
data
は、バックアップする ArrayList
の名前であると想定しています。その場合、 clone
は deep ではないことを知っておく必要があります-呼び出されるオブジェクト(この場合はリスト)のコピーのみを作成します。ディープクローンの場合、新しいリストにその中のオブジェクトのクローンが格納されます。
深くないため、リストに含まれるオブジェクトを変更すると、同じオブジェクトが含まれているため、バックアップリストにもそれらの変更が表示されます。 「現在」を変更した後、バックアップに変更が表示されないのは、 listは、現在のリストからオブジェクトを追加または削除するときです。
一部のクラスは clone
をオーバーライドして、深くなる場合がありますが、すべてではありません。一般的に、それはあなたが頼ることができるものではありません。 Javaコレクションのバックアップコピーを作成するときは、含まれているオブジェクトも複製するか、不変オブジェクトのコレクションのみを処理することを忘れないでください。
これらのプロセスはすべて浅いコピーを作成します。配列内のオブジェクトのプロパティを変更する場合、2つの配列は同じインスタンスへの参照を持ちます。
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");
org.get(0)
のため、 copy.get(0).getValue()
は" new val"
も返します。および 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では実行しないことを意味します(同じオブジェクトへの参照のコピーで新しいクローンリストを作成するため)。
クローン作成の問題に関しては、コレクション全体を文字列にシリアル化してからシリアル化して新しいオブジェクトに戻すことでこれを解決したら、これにより、すべてのオブジェクトをシリアライズ可能にし、2つのオブジェクトが実際に単一の3番目のオブジェクトを参照したい場合に取得しますが、シンプルさと有用性のバランスは非常に良好です。
実際、これは試していませんが、おそらくパイプを使用して、正確に同時にシリアル化およびシリアル化して、メモリに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);
}
2つのArrayListをラップするオブジェクトを作成できます。何かを書いて、両方のデータを同時に追加、削除、変更します。