Hashcode没有正确散列

时间:2014-08-16 12:28:19

标签: java hashmap hashcode string-hashing

我为这个类编写了一个hashcode函数,由于某种原因,当一个键实际存在于HashMap中时,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%的时间它应该(我们甚至重新输入完​​全相同的情况,有时候它有效但有时它没有)我在过去尝试过很多问题get包含适用于HashMapSet的方法,我想知道为什么这个实现特别困难。 (基本上,错误可能是什么)

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

查询后跟其结果,长数字代表所有键后跟换行符号

2 个答案:

答案 0 :(得分:2)

  

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

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

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

您需要保持等式检查与哈希代码一致 - 在您的情况下,这将检查coordinates的相等性:

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

答案 1 :(得分: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方法的地方)但是我不想完全实现HashMap / Set在Java中。

如果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()

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