在Java中散列密钥

时间:2012-11-03 10:08:32

标签: java hashmap hashtable string-hashing

在java中,当我使用String作为Hashmap的键时,我得到的结果与使用字符串hashcode作为HashMap中的键时的结果略有不同。

有什么见解?

5 个答案:

答案 0 :(得分:12)

  

当我使用字符串哈希码作为HashMap中的键时。

不得使用哈希码本身作为密钥。散列码不是唯一的 - 完全允许两个不相等的值具有相同的散列码。您应该使用字符串本身作为键。然后,地图将首先比较哈希码(以便快速缩小候选匹配),然后与equals进行比较,以获得真正的字符串相等。

当然,假设你的代码确实像你的问题那样,例如。

HashMap<String, String> goodMap = new HashMap<String, String>();
goodMap.put("foo", "bar");

HashMap<Integer, String> badMap = new HashMap<Integer, String>();
badMap.put("foo".hashCode(), "bar");

如果这确实是您的代码的样子,请改用HashMap<String, String>

来自Object.hashCode()的文件(强调我的):

  

hashCode的一般合约是:

     
      
  • 每当在执行Java应用程序期间多次在同一对象上调用它时,hashCode方法必须始终返回相同的整数,前提是不修改对象的equals比较中使用的信息。从应用程序的一次执行到同一应用程序的另一次执行,此整数不需要保持一致。
  •   
  • 如果两个对象根据equals(Object)方法相等,则对两个对象中的每一个调用hashCode方法必须生成相同的整数结果。
  •   
  • 如果两个对象根据equals(java.lang.Object)方法不相等,则不需要在两个对象中的每一个上调用hashCode方法必须产生不同的整数结果。但是,程序员应该知道为不等对象生成不同的整数结果可能会提高哈希表的性能。
  •   

答案 1 :(得分:3)

当然。不同的字符串可以具有相同的hashCode,因此如果在地图中存储两个这样的字符串作为键,则将有两个条目(因为字符串不同)。 Whareas如果你使用他们的hashCode作为密钥,你将只有一个条目(因为他们的hashCode是相同的)。

hashCode不用于判断两个键是否相等。它仅用于为密钥分配存储桶。找到存储桶后,将桶中包含的每个密钥与等于的新密钥进行比较,如果找不到相同的密钥,则将密钥添加到存储桶中。

答案 2 :(得分:3)

问题是,即使两个对象不同,也不意味着它们的哈希码也不同。

两个不同的对象可以共享相同的哈希码。所以,你不应该把它们作为HashMap密钥。

此外,由于Object.hashCode()方法返回的哈希码属于int类型,因此您只能拥有2^32个不同的值。这就是为什么你会根据散列算法对不同的对象进行“碰撞”。

简而言之: -

!obj.equals(obj1)无法确保obj.hashCode() != obj1.hashCode()

答案 3 :(得分:1)

对于相同的String,

HashCodes可以相同或不同,所以要小心。可能这就是为什么你会得到不同的结果。

这是another SO question。请参阅Jon Skeet接受的答案。

答案 4 :(得分:0)

只有当哈希函数是一个完美的哈希值时,你才能使用哈希码作为密钥(参见例如 GPERF)。只要您的关键对象不在内存中,您就可以节省内存。