我为这个类编写了一个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包含适用于HashMap
和Set
的方法,我想知道为什么这个实现特别困难。 (基本上,错误可能是什么)
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
查询后跟其结果,长数字代表所有键后跟换行符号
答案 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()
。
同等问题可能会出现同样的问题。