Java Map::hashCode() 冲突 - 为什么?

发布于 2024-09-17 12:08:39 字数 787 浏览 7 评论 0原文

以下代码会为两个映射生成相同的哈希码,有什么想法吗?


import java.util.HashMap;
import java.util.Map;

public class Foo
{
    @SuppressWarnings("unchecked")
    public static void main (String[] args)
    {
        Map map;

        map = new HashMap();

        map.put("campaignId", 4770L);
        map.put("location", "MINI_PROFILE");
        map.put("active", "true");
        map.put("lazy", true);

        System.out.println(map.hashCode());

        map = new HashMap();

        map.put("campaignId", 4936L);
        map.put("location", "MINI_PROFILE");
        map.put("active", "true");
        map.put("lazy", false);

        System.out.println(map.hashCode());


    }
}

结果是:

-1376467648
-1376467648

只需更改键名就足以使代码生成两个不同的哈希码。

The following code results in the same hash code being generated for the two maps, any ideas?


import java.util.HashMap;
import java.util.Map;

public class Foo
{
    @SuppressWarnings("unchecked")
    public static void main (String[] args)
    {
        Map map;

        map = new HashMap();

        map.put("campaignId", 4770L);
        map.put("location", "MINI_PROFILE");
        map.put("active", "true");
        map.put("lazy", true);

        System.out.println(map.hashCode());

        map = new HashMap();

        map.put("campaignId", 4936L);
        map.put("location", "MINI_PROFILE");
        map.put("active", "true");
        map.put("lazy", false);

        System.out.println(map.hashCode());


    }
}

The result is:

-1376467648
-1376467648

Simply changing the key names is enough to make the code generate two different hash codes.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

甜是你 2024-09-24 12:09:21

这并非巧合。

两者中的字符串对象是相同的。相同的对象将给出相同的哈希码。

It is not a coincident.

String objects are same in both. Same object will give same hashcode.

你没皮卡萌 2024-09-24 12:09:14

发生碰撞。事实上,您可以重写 hashCode() 以始终为每个 HashMap 返回 0,这将是正确的(尽管它会使许多结构变慢)。

Collisions happen. In fact, you could override hashCode() to always return 0 for every HashMap and it would be correct (altough it would make a lot of structures slow).

飘过的浮云 2024-09-24 12:09:08

我认为这只是一个巧合。来自 AbstractMap#hashCode() 的 Javadoc:

映射的哈希码定义为映射的entrySet()视图中每个条目的哈希码之和。

对于 Entry#hashCode():

返回此映射条目的哈希码值。映射条目 e 的哈希码定义为:

 (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
 (e.getValue()==null ? 0 : e.getValue().hashCode())

因此映射的哈希码基于映射中包含的键和值。您只是遇到了一种奇怪的情况,两个映射具有相同的哈希码,没有明显的原因。

I think this is just a coincidence. From the Javadoc for AbstractMap#hashCode():

The hash code of a map is defined to be the sum of the hash codes of each entry in the map's entrySet() view.

And for Entry#hashCode():

Returns the hash code value for this map entry. The hash code of a map entry e is defined to be:

 (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
 (e.getValue()==null ? 0 : e.getValue().hashCode())

So hash codes for maps are based on both the keys AND the values contained in the map. You're just experiencing a odd situation where two maps have the same hash code, with no apparent reason.

此刻的回忆 2024-09-24 12:09:01

我怀疑这只是巧合……肯定会发生冲突,在这种情况下,第一个值中的相关不同位看起来实际上正在丢失。

然而,它不应该有任何区别 - 任何使用哈希码的东西必须应对冲突。

编辑:这只是哈希值的计算方式。此代码显示了发生的情况:

import java.util.*;

public class Test
{
    @SuppressWarnings("unchecked")
    public static void main (String[] args)
    {
        AbstractMap.SimpleEntry[] entries = {
            new AbstractMap.SimpleEntry("campaignId", 4770L),
            new AbstractMap.SimpleEntry("campaignId", 4936L),
            new AbstractMap.SimpleEntry("lazy", true),
            new AbstractMap.SimpleEntry("lazy", false)
        };
        for (AbstractMap.SimpleEntry entry : entries) {
            System.out.println(entry + ": " + entry.hashCode());
        }
    }
}

结果:

campaignId=4770: -1318251287
campaignId=4936: -1318251261
lazy=true: 3315643
lazy=false: 3315617

因此,在一对中,第一个映射的哈希值比第二个映射少 26,而在另一对中,第一个映射的哈希值 em> 比第二张地图。

AbstractMap 只是对哈希值求和(确保排序无关的一种方法),因此两者最终得到相同的哈希码。

这实际上取决于 Boolean.hashCode() ,如下所示:

return value ? 1231 : 1237;

... 和 Long.hashCode() ,如下所示:

return (int)(value ^ (value >>> 32));

鉴于他们碰巧选择的值Boolean.hashCode(),如果您的 long 值仅相距 26(或 26 * 2^32 相距),那么您将遇到同样的情况。

Simply coincidence, I suspect... there are bound to be collisions, and in this case it looks like the relevant different bits in the first value are being lost, effectively.

However, it shouldn't make any difference - anything using hash codes must cope with collisions.

EDIT: It's just the way the hashes happen to be calculated. This code shows what's going on:

import java.util.*;

public class Test
{
    @SuppressWarnings("unchecked")
    public static void main (String[] args)
    {
        AbstractMap.SimpleEntry[] entries = {
            new AbstractMap.SimpleEntry("campaignId", 4770L),
            new AbstractMap.SimpleEntry("campaignId", 4936L),
            new AbstractMap.SimpleEntry("lazy", true),
            new AbstractMap.SimpleEntry("lazy", false)
        };
        for (AbstractMap.SimpleEntry entry : entries) {
            System.out.println(entry + ": " + entry.hashCode());
        }
    }
}

Results:

campaignId=4770: -1318251287
campaignId=4936: -1318251261
lazy=true: 3315643
lazy=false: 3315617

So in one pair the first map has a hash 26 less than the second map, and in another pair the first map has a hash 26 more than the second map.

AbstractMap just sums hash values (one way of making sure that ordering is irrelevant) so the two end up with the same hash code.

It's really down to Boolean.hashCode() which looks like this:

return value ? 1231 : 1237;

... and Long.hashCode() which looks like this:

return (int)(value ^ (value >>> 32));

Given the values they happened to pick in Boolean.hashCode(), if your long values are only 26 apart (or 26 * 2^32 apart) then you'll run into the same thing.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文