相同 class 内的克隆函数

Clone function inside the same class

我正在用 java 进行一些模拟。我正在尝试提前几步模拟树的一个节点,然后丢弃所有更改并返回到原始状态。但是 clone() 没有 return 我正确的结果。

节点class:

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()
}

}

追踪器class:

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

玩家Class:

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

将您的克隆方法更改为:

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 修改,您也需要为每个元素制作副本。目前你有两个 hashmap 副本,但每个副本都有指向同一个对象的引用。因此,在一个哈希图中编辑对象会更改另一个哈希图中的对象。你可以这样做:

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 没有对对象的引用,只有原始类型,现在应该可以正常工作了。