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