我在将HashMap A复制到HashMap B时遇到问题.B总是与A相同。我的想法是仅使用HashMaps制作小型游戏。
Map<Point,Tile> A = new HashMap<Point,Tile>();
HashMap有两件事。一个点(键)和一个tile对象,这是我做的另一个类。 Tile包含两个整数和一个字符串。 (new Tile(x,y,string))。前两个整数定义了点x和y,字符串告诉它是“OFF”还是“ON”。
我首先要做的是用2 * 2元素填充HashMap A.
for(int i=0; i<2;i++){
for(int j=0; j<2;j++){
Tile t = new Tile(i, j, "OFF");
A.put(new Point(i,j), t);
}
}
然后我通过在构造函数中添加A来将HashMap A复制到HashMap B.我的想法是这样我可以通过在构造函数中使用HashMap B返回默认的HashMap A(参见后面的内容)
Map<Point,Tile> B = new HashMap<Point,Tile>(A);
然后我将tile(1,1)更改为“ON”
Tile t2 = A.get(new Point(1,1));
t2.setS("ON");
我的一块瓷砖现在是“开启”。现在我想将电路板重置回原始状态(在人口阶段之后)。我清除HashMap A并使用HashMap B作为构造函数创建一个新的HashMap。
A.clear();
A = new HashMap<Point,Tile>(B);
但是,当我在HashMap A上将tile(1,1)更改为ON时,它也更新了HashMap B.我认为使用构造函数创建一个新的HashMap会创建一个新的副本,但似乎不起作用。
奇怪的是那个
Map<Point,String> A = new HashMap<Point,String>();
会工作但不会
Map<Point,Tile> A = new HashMap<Point,Tile>();
我想以某种方式获取HashMap A的原始内容,而我没有尝试再次遍历这些元素。
这是我的主要类代码
package main;
import java.awt.Point;
import java.util.HashMap;
import java.util.Map;
import model.Tile;
public class Test {
public static void main(String[] args) {
//list1
Map<Point,Tile> A = new HashMap<Point,Tile>();
//Populating map
for(int i=0; i<2;i++){
for(int j=0; j<2;j++){
Tile t = new Tile(i, j, "OFF");
A.put(new Point(i,j), t);
}
}
//copying list1 to list2
Map<Point,Tile> B = new HashMap<Point,Tile>(A);
//Change tile on 1,1 to ON
Tile t2 = A.get(new Point(1,1));
t2.setS("ON");
for(int i=0; i<2;i++){
for(int j=0; j<2;j++){
Tile tTemp = A.get(new Point(i,j));
System.out.println(i+" "+j+" "+tTemp.getS());
}
}
//Reseting tiles
//clear first list
A.clear();
System.out.println("");
//copy second list to first list
A = new HashMap<Point,Tile>(B);
for(int i=0; i<2;i++){
for(int j=0; j<2;j++){
Tile tTemp = A.get(new Point(i,j));
System.out.println(i+" "+j+" "+tTemp.getS());
}
}
}
}
这是tile类
package main;
public class Tile {
public int x,y;
public String s;
public Tile(int x1, int y1, String st){
x=x1;
y=y1;
s=st;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
}
以下是清除HashMap A之前要打印的内容
0 0 OFF
0 1 OFF
1 0 OFF
1 1 ON
这是打印的内容清除HashMap A然后将B复制到它之后。
0 0 OFF
0 1 OFF
1 0 OFF
1 1 ON
没有区别。
答案 0 :(得分:1)
您需要通过克隆 <{1}}对象深层复制您的HashMap
。
默认情况下,Tile
构造函数正在执行浅拷贝。它只是复制传入的HashMap
中的值,这些值适用于原语,Map
s(以及其他不可变的对象)但不能对于String
类型的引用,因为复制的引用将指向相同的原始对象,因此稍后会对其进行修改。
因此,要解决此问题,只需将深层复制方法实现为
Object
并将public Map<Point, Tile> getDeepCopy(Map<Point, Tile> source) {
Map<Point, Tile> copy = new HashMap<Point, Tile>();
for (Map.Entry<Point, Tile> entry : source.entrySet())
copy.put(entry.getKey(), entry.getValue().clone());
return copy;
}
类实现Tile
和覆盖 Cloneable
方法设为
clone()
您使用public class Tile implements Cloneable {
// other implementation
public Tile clone() throws CloneNotSupportedException {
return (Tile) super.clone();
}
}
的方式,我也没有看到Point
它们的需要,但如果您希望它们也被深度克隆,只需将其修改为上面clone()
。
答案 1 :(得分:0)
但是,当我在HashMap A上将tile(1,1)更改为ON时,它也更新了HashMap B.
当你写:
Tile t2 = A.get(new Point(1,1));
t2.setS("ON");
你没有改变任何一张地图。这些地图只引用了Point
个对象和Tile
个对象。它们具有相同的引用 - 复制地图不会克隆其中的对象。
因此,当您更改其中一个对象的内容时,无论您使用哪个地图导航到该对象,都会看到该更改。
换句话说,请考虑以下情况:
如果使Point
和Tile
类不可变,这将不会成为问题 - 因为您将无法更改现有对象的内容。此时,复制引用和克隆对象之间没有特别有意义的区别。你最终会写出类似的东西:
Point p = new Point(1, 1);
Tile t2 = A.get(p);
t2 = t2.withS("ON"); // This would return a reference to a new object
A.put(t2);
答案 2 :(得分:0)
Map<Point,Tile> B = new HashMap<Point,Tile>(A);
制作了A
地图的浅表副本。它不会创建Point
和Tile
值的副本。它使用与原始Map中相同的引用。因此,当您更改B
地图中的平铺时,A
地图中相同的平铺会发生变化,反之亦然。
Map<Point,String> A = new HashMap<Point,String>();
有效
因为String是不可变的,所以与Tile
个实例不同,你不能改变String
的状态。
要创建A的深层副本,您必须迭代A的条目,创建每个键和值的副本(假设Point键和Tile值都是可变的 - 如果Point不可变,它足以创建Tile值的副本),并将副本放在B地图中。
答案 3 :(得分:0)
Map<Point,Tile> B = new HashMap<Point,Tile>(A);
在需要深层复制时制作浅色副本。您要么手动实现深层复制,要么使用某些库为您执行此操作。像这样:
答案 4 :(得分:0)
此处使用此实用程序类执行深度克隆。
//copying list1 to list2
Map<Point,Tile> B = DeepCopy.deepCopy(original)(A);
公用事业类:
public final class DeepClone {
private DeepClone(){}
public static <X> X deepClone(final X input) {
if (input == null) {
return input;
} else if (input instanceof Map<?, ?>) {
return (X) deepCloneMap((Map<?, ?>) input);
} else if (input instanceof Collection<?>) {
return (X) deepCloneCollection((Collection<?>) input);
} else if (input instanceof Object[]) {
return (X) deepCloneObjectArray((Object[]) input);
} else if (input.getClass().isArray()) {
return (X) clonePrimitiveArray((Object) input);
}
return input;
}
private static Object clonePrimitiveArray(final Object input) {
final int length = Array.getLength(input);
final Object copy = Array.newInstance(input.getClass().getComponentType(), length);
// deep clone not necessary, primitives are immutable
System.arraycopy(input, 0, copy, 0, length);
return copy;
}
private static <E> E[] deepCloneObjectArray(final E[] input) {
final E[] clone = (E[]) Array.newInstance(input.getClass().getComponentType(), input.length);
for (int i = 0; i < input.length; i++) {
clone[i] = deepClone(input[i]);
}
return clone;
}
private static <E> Collection<E> deepCloneCollection(final Collection<E> input) {
Collection<E> clone;
// this is of course far from comprehensive. extend this as needed
if (input instanceof LinkedList<?>) {
clone = new LinkedList<E>();
} else if (input instanceof SortedSet<?>) {
clone = new TreeSet<E>();
} else if (input instanceof Set) {
clone = new HashSet<E>();
} else {
clone = new ArrayList<E>();
}
for (E item : input) {
clone.add(deepClone(item));
}
return clone;
}
private static <K, V> Map<K, V> deepCloneMap(final Map<K, V> map) {
Map<K, V> clone;
// this is of course far from comprehensive. extend this as needed
if (map instanceof LinkedHashMap<?, ?>) {
clone = new LinkedHashMap<K, V>();
} else if (map instanceof TreeMap<?, ?>) {
clone = new TreeMap<K, V>();
} else {
clone = new HashMap<K, V>();
}
for (Entry<K, V> entry : map.entrySet()) {
clone.put(deepClone(entry.getKey()), deepClone(entry.getValue()));
}
return clone;
}
}