Copying HashMap to another HashMap

I am having a problem copying a HashMap A to HashMap B. B is always same as A. My idea is making a small tile game using HashMaps only.

Map<Point,Tile> A = new HashMap<Point,Tile>();

HashMap has 2 things. A point(key) and a tile object, which is another class I have made. Tile takes in two integers and a string. ( new Tile(x,y,string)). First two integers defines the point x and y and the string tells if its "OFF" or "ON".

What I do first is populate HashMap A with 2*2 elements.

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

Then I copy HashMap A to HashMap B by adding A in constructor. My idea is so I can go back to default HashMap A by using HashMap B in the constructor(See later)

Map<Point,Tile> B = new HashMap<Point,Tile>(A);

Then I change tile (1,1) to "ON"

Tile t2 = A.get(new Point(1,1));
t2.setS("ON");

One of my tiles is "ON" now. Now I want to reset the board back to original(After the population stage). I clear HashMap A and make a new HashMap with HashMap B as the constructor.

A.clear();
A = new HashMap<Point,Tile>(B);

However, when I changed tile (1,1) to ON on HashMap A , it updated HashMap B as well. I thought making a new HashMap with a constructor will make a new copy of it, but doesn't seem to work.

The strange thing is that

Map<Point,String> A = new HashMap<Point,String>(); 

would work but not

Map<Point,Tile> A = new HashMap<Point,Tile>(); 

I want to somehow get the Original contents of HashMap A without me trying to loop over the elements again.

Here's my main class code

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

    }

}

Here's the tile class

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

}

Here's what is getting printed before clearing HashMap A

0 0 OFF
0 1 OFF
1 0 OFF
1 1 ON

Here's what is getting printed After clearing HashMap A and then copy B to it.

0 0 OFF
0 1 OFF
1 0 OFF
1 1 ON

No difference.

Jon Skeet
people
quotationmark

However, when I changed tile (1,1) to ON on HashMap A , it updated HashMap B as well.

When you write:

Tile t2 = A.get(new Point(1,1));
t2.setS("ON");

you're not changing either of the maps. The maps just have references to Point objects and Tile objects. They have the same references - copying the map doesn't clone the objects within them.

So when you change the contents of one of those objects, you'll see that change regardless of which map you use to navigate to the object.

To put it another way, consider this situation:

  • I write my address on two pieces of paper
  • I give one piece of paper to Charlie and one to Joe
  • Charlie uses the piece of paper to find my house and paints my front door red
  • Joe uses the piece of paper to find my house and observe the colour of the door

Joe will see a red front door, yes? It's exactly the same here.

If you make your Point and Tile classes immutable, this won't be a problem - because you wouldn't be able to change the contents of existing objects. At that point there's no particularly meaningful difference between copying a reference and cloning the object. You'd end up writing something like:

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

people

See more on this question at Stackoverflow