5

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

有什么见解吗?

4

5 回答 5

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 方法都必须产生不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同的整数结果可能会提高哈希表的性能。
于 2012-11-03T10:11:04.250 回答
3

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

hashCode 不用于判断两个键是否相等。它仅用于将存储桶分配给密钥。一旦找到bucket,bucket中包含的每个key都会与新的key进行equals比较,如果找不到equal key,则将该key添加到bucket中。

于 2012-11-03T10:11:53.100 回答
3

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

两个不同的对象可以共享相同的哈希码。因此,您不应该将它们作为 HashMap 键。

Object.hashCode()另外,因为从方法返回的哈希码是 type int,你只能有2^32不同的值。这就是为什么对于不同的对象,您将根据散列算法产生“冲突”。

简而言之: -

!obj.equals(obj1)不能确保obj.hashCode() != obj1.hashCode().

于 2012-11-03T10:12:41.640 回答
1

HashCodes同一个字符串可以相同或不同,所以要小心。可能这就是你得到不同结果的原因。

这是另一个关于它的问题。请参阅 Jon Skeet 接受的答案。

于 2012-11-03T10:14:06.027 回答
0

只有当散列函数是完美散列时,才能使用散列码作为键(参见例如 GPERF)。只要您的关键对象不驻留在内存中,您就可以节省内存。

于 2014-02-01T20:03:47.343 回答