次のようなサンプルプログラムがあります。
ArrayList<Invoice> orginalInvoice = new ArrayList<Invoice>();
//add some items into it here
ArrayList<Invoice> copiedInvoice = new ArrayList<Invoice>();
copiedInvoice.addAll(orginalInvoice);
copiedInvoice
内の項目を変更できると考えましたが、originalInoice
内のこれらの項目には影響しません。しかし、私は間違っていました。
ArrayList
のコピー/クローンを分離するにはどうすればよいですか?
ありがとう
はい、それは正しいです-clone()
(またはclone()
は多くのプログラマーによって「壊れた」と見なされるため、オブジェクトをコピーするための別の適切なメカニズムを実装する必要があります。 clone()
メソッドは、オブジェクト内のすべての可変フィールドのディープコピーを実行する必要があります。そうすれば、複製されたオブジェクトを変更しても元のオブジェクトには影響しません。
サンプルコードでは、2番目のArrayList
を作成し、同じオブジェクトへの参照を設定しています。これが、オブジェクトの変更が両方のList
sから見える理由です。 。クローンアプローチでは、コードは次のようになります。
_List<Foo> originalList = ...;
// Create new List with same capacity as original (for efficiency).
List<Foo> copy = new ArrayList<Foo>(originalList.size());
for (Foo foo: originalList) {
copy.add((Foo)foo.clone());
}
_
[〜#〜] edit [〜#〜]:明確にするために、上記のコードは、元のList
の-ディープコピーを実行しています。これにより、新しいList
には、元のオブジェクトのコピーへの参照が含まれます。これは、List
の_shallow copy
_を実行するArrayList.clone()
の呼び出しとは対照的です。このコンテキストでは、浅いコピーは新しいList
インスタンスを作成しますが、元のオブジェクトへの参照を含みます。
可変オブジェクトをArrayListに保存している場合、ArrayListをコピーするときに各オブジェクトをコピーする必要があります。それ以外の場合、新しいArrayListは元の参照を保持します。
ただし、不変オブジェクトを格納している場合は、次を使用しても問題ありません。
ArrayList copiedInvoice = new ArrayList(originalInvoice);
copyedInvoice内の項目を変更できると思ったので、originalInoice内のこれらのitmeには影響しません。
これは、コピーされるのは参照変数であり、オブジェクト自体ではないためです。
したがって、同じオブジェクトを指す2つの「参照」になります。
オブジェクト全体をコピーする必要がある場合は、クローンを作成する必要があります。
ただし、オブジェクトの内部属性が他のオブジェクトである場合、それらのクローンを作成しないと問題が発生する可能性があります。
たとえば、次のクラス定義では問題はありません。
public class Something {
private int x;
private int y;
private String stringObject;
}
そのコピーを作成すると、その属性の現在の値がコピーされ、それだけです。
ただし、クラスに別のオブジェクトが含まれている場合は、それも複製することを検討してください。
class OtherSomething {
Something something;
private int x;
}
以下を行う場合:
Something shared = new Something();
OtherSomething one = new OtherSomething();
OtherSomething two = new OtherSomething();
one.something = shared;
two.something = shared;
この場合、1つと2つの両方が同じ共有「何か」への同じ参照変数を持ち、一方の値を変更すると他方に影響します。
そのため、不変オブジェクトを使用する方がはるかに簡単/より良い/簡単です。
不変オブジェクトの値を変更する必要がある場合は、正しい値で新しいオブジェクトを作成するだけです。