Javaでコピーする必要があるオブジェクトがあります。元のオブジェクト自体を変更せずに、コピーを作成し、その上でいくつかのテストを実行する必要があります。
Clone()メソッドを使用する必要があると思いましたが、これは保護されています。ネットで調査を行った結果、これがクラスのパブリックメソッドでオーバーライドできることがわかります。しかし、これを行う方法についての説明は見つかりません。これはどのように行うことができますか?
また、これは私が必要とするものを達成するための最良の方法ですか?
コピーコンストラクターを使用する別のオプション( Javaプラクティス から):
public final class Galaxy {
public Galaxy (double aMass, String aName) {
fMass = aMass;
fName = aName;
}
/**
* Copy constructor.
*/
public Galaxy(Galaxy aGalaxy) {
this(aGalaxy.getMass(), aGalaxy.getName());
//no defensive copies are created here, since
//there are no mutable object fields (String is immutable)
}
/**
* Alternative style for a copy constructor, using a static newInstance
* method.
*/
public static Galaxy newInstance(Galaxy aGalaxy) {
return new Galaxy(aGalaxy.getMass(), aGalaxy.getName());
}
public double getMass() {
return fMass;
}
/**
* This is the only method which changes the state of a Galaxy
* object. If this method were removed, then a copy constructor
* would not be provided either, since immutable objects do not
* need a copy constructor.
*/
public void setMass( double aMass ){
fMass = aMass;
}
public String getName() {
return fName;
}
// PRIVATE /////
private double fMass;
private final String fName;
/**
* Test harness.
*/
public static void main (String... aArguments){
Galaxy m101 = new Galaxy(15.0, "M101");
Galaxy m101CopyOne = new Galaxy(m101);
m101CopyOne.setMass(25.0);
System.out.println("M101 mass: " + m101.getMass());
System.out.println("M101Copy mass: " + m101CopyOne.getMass());
Galaxy m101CopyTwo = Galaxy.newInstance(m101);
m101CopyTwo.setMass(35.0);
System.out.println("M101 mass: " + m101.getMass());
System.out.println("M101CopyTwo mass: " + m101CopyTwo.getMass());
}
}
2つの一般的なアプローチがあります。 1つは、あなたが述べたようにclone
メソッドを提供することです。
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
どちらか適切な方を選択することをお勧めします。
単体テストでは、リフレクションコピーや即時シリアル化/逆シリアル化などの他のアプローチを使用します。私には、主にパフォーマンスの懸念のために、量産コードにはあまり適していないと感じています。
いくつかのオプション:
Cloneable
を実装し、clone()
メソッドをパブリックとして配置できます。詳細な説明はこちら: http://www.cafeaulait.org/course/week4/46.htmlSerializable
インターフェースを実装する必要があります。XStream
を使用して、XMLによるシリアル化を実行できます。ここでは何も実装する必要はありません。テストコードの場合、シリアル化がおそらく最も安全な答えです。特に、オブジェクトがすでにシリアル化可能である場合は、実装にApache Commons SerializationUtilsを試してください。
オブジェクトの複製にはorg.Apache.commons.lang3.SerializationUtilsクラスを使用できます-クラスはSerializableインターフェースを実装する必要があります。
SerializationUtils.cloneはGoogle App Engineインスタンスでもサポートされています
Javaでオブジェクトをコピーする方法はいくつかあります(浅いまたは深い)。
これ Answer が役立ちます。
Joshua Blochには 複製可能についていくつか興味深い点があります があります。オブジェクトのサイズ/構造に応じて、コピーコンストラクターをオブジェクトに追加するか、上記のソリューションの1つを使用してシリアル化/逆シリアル化します。