将HashMap复制到另一个HashMap

时间:2015-03-19 07:56:46

标签: java dictionary hashmap copy

我在将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

没有区别。

5 个答案:

答案 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个对象。它们具有相同的引用 - 复制地图不会克隆其中的对象。

因此,当您更改其中一个对象的内容时,无论您使用哪个地图导航到该对象,都会看到该更改。

换句话说,请考虑以下情况:

  • 我在两张纸上写下我的地址
  • 我给查理一张纸,一张给乔
  • 查理用这张纸找到我的房子并将我的前门涂成红色
  • 乔用这张纸找到我的房子并观察门的颜色
乔会看到一个红色的前门,对吗?这里完全一样。

如果使PointTile类不可变,这将不会成为问题 - 因为您将无法更改现有对象的内容。此时,复制引用和克隆对象之间没有特别有意义的区别。你最终会写出类似的东西:

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地图的浅表副本。它不会创建PointTile值的副本。它使用与原始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); 

在需要深层复制时制作浅色副本。您要么手动实现深层复制,要么使用某些库为您执行此操作。像这样:

Java Deep-Cloning library

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

参考:Assigning Hashmap to Hashmap