当我将一个元素添加到 java HashSet 时,所有元素都会发生变化
When I add an element to a java HashSet, all the elements change
在 Conway 的生命游戏模拟器中,我有八个看起来像这样的代码块来查找单元格的邻域。
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是代表当前单元格的点,data是包含活跃单元格的HashSet。为了提高效率,我只检查与活细胞相邻的死细胞,因此 deadCellsToCheck 是另一个 HashSet,它在每一代开始时都是空的。每次我执行 deadCellsToCheck.add(p) 时,似乎所有已经在其中的单元格都被覆盖为刚刚添加的单元格,因为输出如下所示:
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...
出于多种原因,我认为这不可能。有什么想法吗?
这个问题的原因是您的 HashSet
多次包含相同的 Point
实例。您应该创建一个新点并将其添加到集合中,而不是编辑点 p.setLocation(p.x-1, p.y-1);
:
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();
}
您当前的结构也违反了 hashCode()
方法的约定:
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
集合使用hashCode
和equals
方法来消除重复。您创建了具有 hashcode = 0
的点 (0,0)
。然后将点修改为 (1,0)
,它的 haschode 更改为 1072693248
因此集合允许再次插入该点。但它是同一个实例 - 它是同一个对象两次插入集合中。
通常不应该在集合或依赖于 hashcode
方法的其他数据结构中使用可变对象。
解决方案是使点不可变(如果您使用 java.awt.Point
,我建议您创建自己的 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
}
看起来你在一遍又一遍地向集合中添加一个点,并改变它的值。如果你想添加一堆不同的点,你需要制作一堆新的点对象(使用单词new
)而不是一个。
在 Conway 的生命游戏模拟器中,我有八个看起来像这样的代码块来查找单元格的邻域。
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是代表当前单元格的点,data是包含活跃单元格的HashSet。为了提高效率,我只检查与活细胞相邻的死细胞,因此 deadCellsToCheck 是另一个 HashSet,它在每一代开始时都是空的。每次我执行 deadCellsToCheck.add(p) 时,似乎所有已经在其中的单元格都被覆盖为刚刚添加的单元格,因为输出如下所示:
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...
出于多种原因,我认为这不可能。有什么想法吗?
这个问题的原因是您的 HashSet
多次包含相同的 Point
实例。您应该创建一个新点并将其添加到集合中,而不是编辑点 p.setLocation(p.x-1, p.y-1);
:
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();
}
您当前的结构也违反了 hashCode()
方法的约定:
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
集合使用hashCode
和equals
方法来消除重复。您创建了具有 hashcode = 0
的点 (0,0)
。然后将点修改为 (1,0)
,它的 haschode 更改为 1072693248
因此集合允许再次插入该点。但它是同一个实例 - 它是同一个对象两次插入集合中。
通常不应该在集合或依赖于 hashcode
方法的其他数据结构中使用可变对象。
解决方案是使点不可变(如果您使用 java.awt.Point
,我建议您创建自己的 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
}
看起来你在一遍又一遍地向集合中添加一个点,并改变它的值。如果你想添加一堆不同的点,你需要制作一堆新的点对象(使用单词new
)而不是一个。