21

Javaでコピーする必要のあるオブジェクトがあります。元のオブジェクト自体を変更せずに、コピーを作成していくつかのテストを実行する必要があります。

clone()メソッドを使用する必要があると想定しましたが、これは保護されています。ネット上でいくつかの調査を行ったところ、これは私のクラスのパブリックメソッドでオーバーライドできることがわかりました。しかし、これを行う方法についての説明が見つかりません。これはどのように行うことができますか?

また、これは私が必要とするものを達成するための最良の方法ですか?

4

7 に答える 7

30

コピーコンストラクタを使用する別のオプション(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());
    }
} 
于 2009-01-24T11:07:22.217 に答える
21

2 つの一般的なアプローチがあります。clone1つは、あなたが言ったようにメソッドを提供することです。

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

どちらか自分に合ったアプローチを選択することをお勧めします。

単体テストでのみ、反射コピーや即時のシリアル化/逆シリアル化などの他のアプローチを使用します。私には、主にパフォーマンス上の懸念から、これらはプロダクション コードにはあまり適していないと感じています。

于 2009-01-24T16:12:55.923 に答える
14

いくつかのオプション:

  • Cloneableオブジェクトを実装し、clone()メソッドをpublicとして配置できます。ここで完全な説明を参照してください:http://www.cafeaulait.org/course/week4/46.html
    ただし、これは浅いコピーを生成し、あなたが望むものではないかもしれません。
  • オブジェクトをシリアル化および逆シリアル化できます。Serializableオブジェクトとそのすべてのフィールドのインターフェースを実装する必要があります。
  • XMLを介してシリアル化を実行するために使用できますXStream。ここで何も実装する必要はありません。
于 2009-01-24T10:49:57.900 に答える
9

テストコードの場合、シリアル化がおそらく最も安全な答えです。特に、オブジェクトがすでにシリアル化可能である場合は、実装のためにApacheCommonsSerializationUtilsを試してください。

于 2009-01-24T11:04:03.833 に答える
2

javaでオブジェクトをコピーする方法は複数あります(浅いまたは深い)。
この回答はあなたを助けます。

于 2012-03-23T07:40:59.250 に答える
2

Joshua Blochには、クローン可能についていくつか興味深いことがあります。オブジェクトのサイズ/構成に応じて、コピーコンストラクターをオブジェクトに追加するか、上記のソリューションのいずれかを使用してシリアル化/逆シリアル化します。

于 2009-01-24T13:51:04.040 に答える