1

我已经hashcode为这个类编写了一个函数,由于某种原因,哈希映射无法正确识别密钥何时实际存在于HashMap. (坐标是一个字符串)

@Override
public int hashCode() {
    return coordinates.hashCode();
}

而且我还.equals为该类编写了一个方法,用于测试两对坐标是否彼此相等;但是,为了验证我的哈希码方法是否正常工作,我已将该.equals方法切换为以下方法。

public boolean equals(Object arg) {
    Block a = (Block) arg;
    return hashCode() == a.hashCode();
}

他们都在其他地方被hashmap.containskey()调用,如下所示:

return (hashblocks.containsKey(newz));

出于某种原因,这只在 50% 的时间里应该返回 true(我们甚至重新输入完​​全相同的情况,有时它会起作用,有时却不起作用)我过去在尝试获取 contains 方法时遇到了很多问题为HashMaps 和Sets 正常工作,我想知道为什么这个实现特别有困难。(基本上,错误可能是什么)

3 1 3 1
true
4 2 4 2
false
 0 0 1 0
 0 3 1 3
 2 0 3 0
 2 3 3 3
0 1 1 2
2 1 2 2
4 0 4 0
4 2 4 2
3 1 3 1
3 2 3 2

3 1 3 1
true
4 2 4 2
true
3 2 3 2
true
 0 0 1 0
 0 3 1 3
 2 0 3 0
 3 3 4 3
0 1 1 2
2 1 2 2
4 0 4 0
4 2 4 2
3 1 3 1
3 2 3 2

查询后跟它的结果,一长串数字代表所有键,后跟换行符

4

2 回答 2

2

为了验证我的哈希码方法是否正常工作,我已将 .equals 方法切换为以下方法。

return hashCode()==a.hashCode();

这仅在“完美散列”的情况下才有效,即当散列码的相等意味着实际值的相等时。Java 中的哈希码String并不完美(事实上,即使在理论上,它们也不可能对所有可能的字符串都是完美的)。

您需要使相等性检查与哈希码保持一致-在您的情况下,这将检查以下内容的相等性coordinates

public boolean equals(Object arg) {
    Block a = (Block) arg;
    return coordinates.equals(a.coordinates);
}
于 2014-08-16T12:32:36.550 回答
2

由于坐标似乎是可变的,因此您不应该将其用作hashCode(),因为您会遇到基于散列的容器的问题,例如:

Map<Object,Object> map = new HashMap<>();
key.setCoordinates("1");
map.put(key, value1); 
key.setCoordinates("2");
map.put(key, value2); 

密钥保持不变,但它hashCode基于coordinates哪个是可变的。在第一种情况下,当 时coordinates == "1",它的值可能是 1。由于哈希映射/集使用具有一定容量(例如 16)的内部数组,它会将 value1 存储在以下位置:

map.values[(key.hashCode() % map.values.length)] = value1;
map.values[(1 % 16)] = value1;
map.values[1] = value1;

实际上,该数组是一个列表数组(例如:两个键可能具有相同的哈希码,这就是使用 equals 方法的地方),但我不想深入了解 Java 中 HashMap/Set 的完整实现。

如果发生hashCode变异,那么put第二次调用将不起作用:假设"2".hashCode()是 2,并且key.hashCode()也返回 2:

map.values[(key.hashCode() % map.values.length)] = value2;
map.values[(2 % 16)] = value2;
map.values[2] = value2;

但是对于同一个键,您已经有一个关联的值,但它并没有被 value2 替换。我什至可以假设System.out.println(map);它将以随机顺序打印[key: value1, key: value2]

这就是为什么一个hashCode方法应该避免使用变异字段的原因,除非你确定当你使用你的地图时,键永远不会变异。

您可能应该返回 0,或使用默认值hashCode()/equals()

equals 可能会出现同样的问题。

于 2014-08-16T13:09:05.437 回答