コンストラクターでオブジェクトのリストを取得するクラスがありますList<Object>
。リストが異なるタイプの要素から作成されるたびに。それは一般的なものであり、クラスの型がどうなるかわかりません。
ユーザーに値を変更させる前に、そのリストのコピーを自分自身に保存したいと思います。しかし、コピーは参照によって行われるため、両方のリスト (元のリストとコピー) が変更されています...
リストを値でコピーするにはどうすればよいですか?
ありがとう、デボラ
コンストラクターでオブジェクトのリストを取得するクラスがありますList<Object>
。リストが異なるタイプの要素から作成されるたびに。それは一般的なものであり、クラスの型がどうなるかわかりません。
ユーザーに値を変更させる前に、そのリストのコピーを自分自身に保存したいと思います。しかし、コピーは参照によって行われるため、両方のリスト (元のリストとコピー) が変更されています...
リストを値でコピーするにはどうすればよいですか?
ありがとう、デボラ
あなたの質問は明確ではありません。
浅いコピー (つまり、元のリスト内のオブジェクトへの参照を含むリストのコピー) が必要な場合は、実装クラスclone
のコピー コンストラクターと同様に、メソッドがジョブを実行します。List
ディープ コピー (つまり、元のオブジェクトのコピーを含むリストのコピー) が必要な場合は、新しいリストを作成し、元のリスト要素のクローンを作成することをお勧めします。ただし、落とし穴があります。このclone
メソッドはデフォルトでは提供されていません。多くの一般的なユーティリティ クラスは複製可能ですが、カスタム クラスは複製できません ... 実装していない限り。リストに複製不可能なオブジェクトが含まれている場合、実行時に例外が発生します。
には他にもディープ コピーの代替手段がありますがclone
、クローンと同様に、すべてのクラスで機能するわけではありません。実際、ソリューションが一般的でなければならない場合、それが問題の核心です。
List
新しいリストを作成してから、元のリストの各要素のクローンをそれに追加する必要があります。
List<Object> copy = new ArrayList<Object>(inputList.size());
for (Object item : inputList) {
copy.add(item.clone());
}
Cloneable
明らかに、リスト内のオブジェクトが正しくコピーされないことを確認する必要があります。
渡されたリストを繰り返し処理し、そのコンテンツを作成して新しいリストを作成します。このリストは、元のリストを変更せずに使用できます。
private List<Object> clone;
public Foo(List<Object> original)
{
this.clone = new ArrayList<Object>(list.size());
for(Object item: original)
{
clone.add(item.clone());
}
}
Collections.copy(b、a);
ドキュメントは次のとおりです:http: //docs.oracle.com/javase/1.4.2/docs/api/java/util/Collections.html#copy%28java.util.List,%20java.util.List%29
オブジェクトに他のオブジェクトの他の参照が含まれていない場合は、Object.clone() を使用できますが、そうでない場合は、ディープ クローンを作成する必要があります。
このような状況では、次の 3 つの一般的な解決策があります。
(1) 個々の要素に意図したとおりに機能するclone()メソッドがあることがわかっている場合は、新しい配列を作成し、対応する各要素の clone() で埋めます。経験則として、JDK の「基本的な」オブジェクト (文字列、数値表現など) は問題ありません。clone() の欠点は、それが少し「緩い大砲」であることです: メソッドが特定のクラスに対してオーバーライドされた場合に「クローン」がどれだけ深くなるか、およびどの参照が潜在的に取得される可能性があるかはアプリオリにわかりません。再利用するかどうか。また、コンストラクターのロジックに依存する複製可能なオブジェクトのサブクラスが機能しない可能性があるという特定の危険性もあります。しかし、私が言うように、単純な JDK オブジェクトで十分です。
(2) ByteArrayOutputStreamにラップされた ObjectOutputStream にリストをシリアル化します。次に、結果のバイト配列を取得し、ByteArrayInputStream と ObjectInputStream をラップして、リストの新しいディープ コピーを読み取ります。
(3) 理想的な世界では、問題のオブジェクトの明示的に作成された「コピー」で埋めて、新しいリストを作成します。コーディングが面倒でない場合、これは理想的なソリューションです。「実際に何が起こっているかを知っている」ためです。オブジェクトが再作成されるのではなく、誤って再参照されるという点で、隠れた驚きはありません。あなたが期待したように動作しませんでした。
構造を簡単に再作成できる単純なコンテナー オブジェクト (配列リスト) があるため、(2) はやり過ぎかもしれません。より複雑な構造を再作成するのに便利です。
(1) に関して は、オブジェクトが clone() を念頭に置いて特別に設計されていないサードパーティのライブラリからオブジェクトを複製することに特に疑念を抱く必要があります。問題は、人々が JDK (クローン可能) クラスまたはトークン clone() メソッドを実際に詳細に考えずにサブクラス化するのは簡単だということです。予期しない問題につながる可能性があることに注意してください (たとえば、新しいオブジェクトでコンストラクターが呼び出されないなど)。したがって、clone() が安全であることを確認するための信頼できるソース コードを実際に見ることができない場合は、それを避けます。
あなたが持っている場合:
List<Object> objects
このリストは次の方法でコピーできます。
List<Object> newObjects = new ArrayList<Object>(objects);
[更新: ArrayList の実際の実装を追加して、新しいオブジェクトがコピーされたことを証明する]
ArrayList の実際の実装を参照してください。オブジェクトをコピーします。同じオブジェクトへの参照は含まれません。
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
size = elementData.length;
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}