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;
    }
}

注意:我不能为此使用 apache 函数,例如 org.apache.commons.lang.SerializationUtils

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,因此更改一个会更改另一个。然而,通过显式创建跟踪器的新副本,两个节点现在拥有 HashMap 的两个副本,因此更改一个不会影响另一个。

这是假设 HashMap 中包含的对象没有被更改。如果是,这些更改将反映在两个副本中。

有关在 Java 中复制的更详细说明,请参阅如何在 Java 中复制对象的第二个答案?

- 编辑 -

如果跟踪器中的现有元素正在被 foo 修改,您也需要制作每个元素的副本。目前,您有两个哈希图副本,但每个副本都有指向同一个对象的引用。因此,在一个哈希图中编辑对象会更改另一个哈希图中的对象。您可以执行以下操作:

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 的对象本身具有正确实现的克隆方法这一事实。否则你最终会遇到同样的问题,他们引用的任何对象都将与原始哈希图中的对象相同。不幸的是,在 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 回答