2 つの一般的なアプローチがあります。clone
1つは、あなたが言ったようにメソッドを提供することです。
public class C implements Cloneable {
@Override public C clone() {
try {
final C result = (C) super.clone();
// copy fields that need to be copied here!
return result;
} catch (final CloneNotSupportedException ex) {
throw new AssertionError();
}
}
「フィールドをコピー...ここに!」に注意してください。部。イニシャルresult
は単なる浅いコピーです。つまり、オブジェクトへの参照がある場合、元のオブジェクトresult
と同じオブジェクトを共有します。たとえば、C
含まれている場合は、private int[] data
おそらくそれをコピーしたいと思うでしょう。
...
final C result = (C) super.clone();
result.data = data.clone();
return result;
...
プリミティブ フィールドの内容は既にコピーされているため、コピーする必要がないことに注意してください。また、変更できないため、不変オブジェクトもコピーする必要はありません。
2 つ目の方法は、コピー コンストラクターを提供することです。
public class C {
public C(final C c) {
// initialize this with c
}
}
またはコピー工場。
public class C {
public static C newInstance(final C c) {
return new C(c);
}
private C(final C c) {
// initialize this with c
}
}
両方のアプローチには、それぞれのプロパティがあります。 clone
メソッドであるため、正確な型を知る必要はありません。最終的には、常に「完璧な」コピーを作成する必要があります。Java コレクションからわかるように、呼び出し元が決定する機会があるため、コピー コンストラクターは便利です。
final List c = ...
// Got c from somewhere else, could be anything.
// Maybe too slow for what we're trying to do?
final List myC = new ArrayList(c);
// myC is an ArrayList, with known properties
どちらか自分に合ったアプローチを選択することをお勧めします。
単体テストでのみ、反射コピーや即時のシリアル化/逆シリアル化などの他のアプローチを使用します。私には、主にパフォーマンス上の懸念から、これらはプロダクション コードにはあまり適していないと感じています。