画面の状態を保存して呼び出すためのシステムに取り組んでいます。この種のものをいじるのは初めてなので、これを行う最善の方法が何であるかはよくわかりませんが、現在すべての「PreviewMonitor」を保存しています配列リスト内のオブジェクト (約 40 程度)。問題は、保存する「allPreviewMonitors」というタイトルの ArrayList のコピーを作成すると、元の要素が更新されるたびに常に変化する要素を持つ ArrayList になってしまうことです。実際には、allPreviewMonitors のコピーを作成したときの要素とその状態の「凍結」バージョンを持つまったく異なる ArrayList であるはずなのに、元の ArrayList で作業しているように見えます。なぜこのような動作が発生するのですか? 必要に応じてコードを表示できますが、ここで必要かどうかはわかりません。
4 に答える
Arraylist
すべてのようCollections
に、オブジェクトへの参照のみが含まれます。リストをコピーするだけでは不十分です。リストのコピーを作成する際に、リスト内の要素を clone() (または新しい要素を作成するか、コピー コンストラクターを使用) する必要があります。
これを「ディープ コピー」の作成と呼びますが、現在は「シャロー コピー」を作成しています。
オブジェクト参照を ArrayList にコピーするだけです。オブジェクト自体をコピーする必要があります。
Java では、すべてのオブジェクト変数は実際には参照変数です。だからコード:
Myclass myObject = new Myclass();
Myclass otherObject = myObject;
Myclass オブジェクトを作成し、その Myclass オブジェクトへの参照を参照変数に格納しますmyObject
。次に、新しい参照変数を作成しotherObject
、参照データ (メモリ アドレスなど) を から にコピーmyObject
しotherObject
ます。これらはメモリ内の同じオブジェクトを参照するようになりました。この時点で、ライン
myObject.myMethod();
と同じ結果が得られます
otherObject.myMethod();
ArrayList で取得しているのは、同じオブジェクトへの異なる参照です。欲しいものは以下のいずれかです。
Myclass otherObject = myObject.clone(); // use the clone function
// OR
Myclass otherObject = new Myclass(myObject); // use a copy constructor
またはコピー コンストラクターを使用してオブジェクトを ArrayList に配置するclone()
と、ArrayList には同じコピーへの参照ではなく、同一のコピーへの参照が含まれます。
他の人が指摘しているように、参照のコピーを作成することは「浅いコピー」と呼ばれ、参照されているオブジェクトのコピーを作成することは「ディープコピー」と呼ばれます。
編集:これが機能するためには、クラスだけでなく、クラスに含めるすべてのクラスにソリューションを実装する必要があります。たとえば、MyClass
type のフィールドを持つものを考えてみましょうOtherClass
。
class MyClass {
private String foo;
private OtherClass bar;
private int x;
MyClass(String f, OtherClass b, int x) {
foo = f;
bar = b;
this.x = x;
}
MyClass(MyClass o) {
//make sure to call the copy constructor of OtherClass
this(new String(o.foo), new OtherClass(o.bar), o.x);
}
// getters and setters
}
OtherClass
これには、コピー コンストラクターも必要であることに注意してください。また、OtherClass
他のクラスを参照する場合は、コピー コンストラクターも必要です。それを回避する方法はありません。
最後に、リストのコピーは次のようになります。
List<MyClass> myNewList = new ArrayList<>(myExistingList.size());
for ( MyClass item : myExistingList) {
// use the copy constructor of MyClass, which uses the copy constructor of OtherClass, etc, etc.
myNewList.add(new MyClass(item))
}
「ディープ コピー」、つまりPreviewMonitor
オブジェクトのクローンを作成する必要があります。デフォルトでは、浅いコピーを行い、同じオブジェクトへの参照を複製するだけです。
クローンを作成するには、現在のオブジェクトを返すだけでは不十分です。現在のオブジェクトと同じ値で新しいオブジェクトを作成する必要があります。つまり、現在のオブジェクトのクラスのコンストラクターを使用して、新しいオブジェクトを作成します。古いオブジェクトと新しいオブジェクトの間で属性が一致していることを確認してください。新しいオブジェクトを返し、元のリストのすべてのオブジェクトに対して繰り返します。