1

私はJavaを学んでいますが、同じ問題に何度も遭遇し続けています

あるオブジェクトの古い状態に効率的に戻すにはどうすればよいですか?

public class Example {
    MyObject myLargeObject;

    public void someMethod(){
        MyObject myLargeMyObjectRecovery = myLargeObject;

        /**
         * Update and change myLargeObject
         */

        if(someCondition){
            //revert to previous state of myLargeObject
            myLargeObject = myLargeMyObjectRecovery;
        }
    }
}

上記は私がコードを機能させたい方法ですが、myLargeObjectとmyLargeObjectRecoveryは同じオブジェクトへの参照であるため、明らかに機能しません。

1つの解決策は、コピーコンストラクターを作成することです。これは小さなオブジェクトには問題ありませんが、大きなオブジェクトがある場合(私のプロジェクトでは、オブジェクトは大きな2D配列であるため、すべてのエントリを反復処理する必要があります)、この方法は間違っていると感じます。

これはJavaで非常に一般的な問題であるに違いありませんが、他の人はどのようにしてそれを回避しますか?

4

4 に答える 4

1

あなたが指摘したように、ディープコピー、またはおそらくシリアル化のいずれか。シリアル化された文字列を保存し、後でそれからオブジェクトを再構築することができます。

于 2013-02-24T13:05:15.917 に答える
0

Mementoパターンは、以前の状態に戻す問題の設計上の問題に対処します。このアプローチは、オブジェクトの1つまたは複数の状態をキャプチャして、それらに戻すことができる必要がある場合に役立ちます。テキストエディタの場合と同様に、Nステップの元に戻す操作と考えてください。

このパターンには、ステートフルオブジェクトがOriginatorあり、その状態のスナップショットの保存と復元を担当します。状態自体は、と呼ばれるラッパークラスに保存されます。このクラスはMemento、に保存され、を介してアクセスされますCareTaker

このアプローチで最も簡単なアイデアは、オブジェクトをディープコピーすることです。ただし、変更セットのみではなくオブジェクト全体を格納するため、これはパフォーマンスとスペースに関して非効率的である可能性があります。

一部のオブジェクト永続性ライブラリは、トランザクションとスナップショットの実装を提供します。Prevaylerを見てください。これは、Java用のオブジェクト永続化ライブラリであり、一般的なシステムパターンの実装です。ライブラリは、オブジェクトへの変更をトランザクションの形式でキャプチャし、それらをメモリに保存します。POJOの永続ストレージが必要な場合は、オブジェクトのスナップショットを定期的にディスクに保存し、必要に応じてそれらに戻すことができます。

POJOのシリアル化の詳細については、このSOの質問を参照してください。オブジェクト変更の追跡/バージョン管理のJava APIはありますか?

于 2013-02-24T14:31:03.567 に答える
0

MyObject最善の解決策は、インスタンスへの外部参照があるかどうかによって異なります。

クラスmyLargeObject からExampleのみ使用する場合は、使用できます

  • セーブポイントでオブジェクトをシリアライズし、復元ポイントでデシリアライズします (シリアライズは であるbyte[]必要がありますtransient)
  • セーブポイントでコピー コンストラクター (ディープ コピーを実行) を使用して新しいインスタンスを作成し、復元ポイントで参照を置き換えます。

外部からMyObjectインスタンスにアクセスできる場合は、もう少し興味深いものになります。同期を導入する必要があります。

  • すべてのメソッドは(一貫性のない読み取りを避けるため)でMyObjectある必要があります。synchronized
  • synchronized void saveState()状態を保存するメソッドが必要です(シリアライゼーションまたはコピーコンストラクターのいずれかによる)(後者の方が優れています)
  • synchronized void restoreState()状態を内部的に復元する必要があります(フィールドをコピーするには、コピーコンストラクターで共通のコードフラグメントを使用できます)

いずれの場合も、ある時点でトランザクション(一種commit()) を閉じることをお勧めします。これは、そこに到達したら、保存された状態を削除できることを意味します。

また、基礎となるデータ構造がある場合は、その構造全体をトラバースする必要があることも非常に重要です。そうしないと、オブジェクト参照で問題が発生する可能性があります。

JPA エンティティまたは外部で管理されるオブジェクトには注意してください。これらのメソッドのいずれかがそれらで機能する可能性は低いです。

于 2013-02-24T13:26:54.277 に答える
0

オブジェクトを別のオブジェクトに割り当てると、jvm はメモリ内の同じオブジェクトを参照します。したがって、オブジェクトの変更は、参照する他の objetc になります。

MyObject myLargeMyObjectRecovery = myLargeObject;

コードでも同じです。メモリ内の同じオブジェクトを参照しますmyLargeMyObjectRecoverymyLargeObject

オブジェクトの正確なコピーが必要な場合は、 Object.clone() メソッドを使用できます。このメソッドはオブジェクトをコピーし、フィールドとその値がコピーされたオブジェクトと同じである別のオブジェクトを参照するオブジェクトを返します。

clone メソッドは保護されているため、直接アクセスすることはできません。要件に応じてプロトタイプ パターンを実装できます。

http://www.avajava.com/tutorials/lessons/prototype-pattern.html

public class MyObject{

//fields, getters, setters and other methods.

public MyObject doClone()
    {
        MyObject clonedObject = this.clone(); //you may need to override clone()depending on your requirements.
return clonedObject;
    }

    }

そしてあなたのコードでそれを呼び出します

MyObject myLargeMyObjectRecovery = myLargeObject.doClone();
于 2013-02-24T13:51:20.833 に答える