0

私はJavaでいくつかのシミュレーションを行っています。ツリーのノードを数ステップ先にシミュレートしてから、すべての変更を破棄して元の状態に戻そうとしています。しかし、 clone() は適切な結果を返しません。

ノード クラス:

public class TreeNode implements Serializable,Cloneable{

HashMap<Integer, Tracker> trackers;

public Object clone(){
    try{
       TreeNode node = (TreeNode) super.clone();
       HashMap<Integer, Tracker> newTrackers = new  HashMap<Integer, Tracker>;
       for (int i=0:i<4:i++){
          newTrackers.put(i, node.trackers.get(i).clone());
       }
       node.trackers = newTrackers;
       return node;
    }catch(CloneNotSupportException e){
    }
    return null;
}

public run(){

    TreeNode current = root;
    TreeNode CopyNode = (TreeNode) current.clone();
    foo(CopyNode);

    //Here both current and CopyNode have the same changes at trackers                                               
    //made by foo()
}

}

トラッカー クラス:

public class Tracker implements Serializable,Cloneable{
    private final Player player;

public Tracker clone(){
   try{
      Tracker newTracker = (Tracker) super.clone();
      newTracker.player = player.clone();
      return newTracker;
    } catch (CloneNotSupportException e){
    }
   return null;
}

プレイヤークラス:

public class Player implements Serializable,Cloneable{
    private int points;

public Player clone(){
   try{
      return (Player) super.clone();
   }catch (CloneNotSupportException e){
   }
       return null;
    }
}

注: org.apache.commons.lang.SerializationUtils のような apache 関数を使用することはできません

4

1 に答える 1

2

クローン方法を次のように変更します。

public TreeNode clone(){
  try {
    TreeNode node = (TreeNode) super.clone();
    node.trackers = (HashMap<Integer, SomeOtherClass>) trackers.clone();
    return node;
  } catch (CloneNotSupportedException e) {
    return null;      
  }
}

以前は、TreeNode の両方のコピーが同じトラッカー HashMap への参照を持っていたため、一方を変更すると他方が変更されました。ただし、トラッカーの新しいコピーを明示的に作成することで、2 つのノードは HashMap の 2 つのコピーを持つようになるため、一方を変更しても他方には影響しません。

これは、HashMap に含まれるオブジェクトが変更されていないことを前提としています。そうである場合、それらの変更は両方のコピーに反映されます。

Java でのコピーの詳細については、How do I copy an object in Java?の 2 番目の回答を参照してください。

- 編集 -

トラッカーの既存の要素が foo によって変更されている場合は、それらのそれぞれのコピーも作成する必要があります。現時点では、ハッシュマップの 2 つのコピーがありますが、それぞれに同じオブジェクトを指している参照があります。したがって、一方のハッシュマップでオブジェクトを編集すると、他方のオブジェクトが変更されます。次のようなことができます:

public TreeNode clone(){
  try {
    TreeNode node = (TreeNode) super.clone();
    HashMap<Integer, SomeOtherClass> newTrackers = new HashMap<>();
    for (Integer key : trackers.keySet()) {
      newTrackers.put(key, trackers.get(key).clone());
    }
    node.trackers = newTrackers;
    return node;
  } catch (CloneNotSupportedException e) {
    return null;      
  }
} 

ただし、これは、トラッカー自体の SomeOtherClass のオブジェクトが適切に実装された clone メソッドを持っているという事実に依存しています。そうしないと、同じ問題が発生し、それらが参照するオブジェクトは元のハッシュマップのものと同じになります。残念ながら、Java では、使用されるすべてのオブジェクトに対して明示的にコーディングしない限り、ディープ クローンを作成する簡単な方法はないようです。

-- 編集 2 --

Tracker クローンを次のように変更します。

public Tracker clone() {
  try {
    Tracker newTracker = (Tracker) super.clone();
    newTracker.player = player.clone();
    return newTracker;
  } catch (CloneNotSupportException e){
  }
  return null;
}

オブジェクトが別のオブジェクトへの参照を持っているときはいつでも、それらも複製する必要があります。Player にはオブジェクトへの参照がなく、プリミティブ型のみであるため、これは適切に機能するはずです。

于 2015-11-14T22:05:12.217 に答える