sam
sam

Reputation: 97

When I add an element to a java HashSet, all the elements change

In a Conway's game of life simulator, I have eight blocks of code that look like this to find the neighborhood of a cell.

int count = 0;
    p.setLocation(p.x-1, p.y-1); //upper left
    if( data.contains(p) ) ++count;
    else if( addingDeadCells ) {
        deadCellsToCheck.add(p);
        for( Point z : deadCellsToCheck ) 
            System.out.println(z.toString() + " " + z.hashCode()); 
        System.out.println();
    }

p is the point representing the current cell, data is a HashSet containing the active cells. For the sake of efficiency I'm only checking dead cells that neighbor live cells, so deadCellsToCheck is another HashSet that starts each generation empty. Each time I execute deadCellsToCheck.add(p), it seems like all the cells already in it get overwritten to be the cell just added, because the output looks like this:

java.awt.Point[x=0,y=0] 0

java.awt.Point[x=1,y=0] 1072693248
java.awt.Point[x=1,y=0] 1072693248

java.awt.Point[x=2,y=0] 1073741824
java.awt.Point[x=2,y=0] 1073741824
java.awt.Point[x=2,y=0] 1073741824
etc...

I don't think this should be possible for multiple reasons. Any ideas?

Upvotes: 0

Views: 1444

Answers (2)

Jaroslaw Pawlak
Jaroslaw Pawlak

Reputation: 5578

The reason of this problem is that your HashSet contains the same instance of Point multiple times. Instead of editing the point p.setLocation(p.x-1, p.y-1); you should be creating a new one and adding it to the set:

int count = 0;
p = new Point(p.x-1, p.y-1); // new point here
if (data.contains(p)) {
     count++;
} else if (addingDeadCells) {
    deadCellsToCheck.add(p);
    for (Point z : deadCellsToCheck)  {
        System.out.println(z.toString() + " " + z.hashCode());
    }
    System.out.println();
}

Your current structure also violates contract of hashCode() method:

Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer

The hashCode and equals methods are used by the set to eliminate duplications. You create point (0,0) which has hashcode = 0. Then you modify the point to (1,0), its haschode changes to 1072693248 so the set allows to insert this point again. But it is the same instance - it is the same object inserted twice into the set.

Mutable objects generally shouldn't be used in sets or other data structures relying on hashcode method.

The solution is to make the point immutable (if you use java.awt.Point, I would recommend to create your own class):

public class Point {

     private final int x;
     private final int y;

     public Point(int x, int y) {
         this.x = x;
         this.y = y;
     }

     // hashcode and equals methods
     // getters and utility methods

}

Upvotes: 6

khelwood
khelwood

Reputation: 59112

It looks like you are adding one point to the set over and over again, and altering its value. If you want to add a bunch of different points, you need to make a bunch of new point objects (use the word new) instead of just one.

Upvotes: 1

Related Questions