克隆函数在同一个类中

时间:2015-11-14 21:58:05

标签: java cloneable

我正在用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

1 个答案:

答案 0 :(得分: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进行复制的更详细说明,请参阅How do I copy an object in 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的对象本身具有正确实现的克隆方法的事实。否则,您将遇到相同的问题,它们引用的任何对象将与原始hashmap中的对象相同。不幸的是,在Java中,似乎没有简单的方法来创建深度克隆,而没有明确地为所有使用的对象编写它。

- 编辑2 -

将您的Tracker克隆更改为:

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

每当一个对象引用另一个对象时,您也需要克隆它们。由于Player没有对象的引用,只有原始类型,因此现在应该可以正常工作。