具有相同哈希码的两个不相等对象

Posted

技术标签:

【中文标题】具有相同哈希码的两个不相等对象【英文标题】:two unequal objects with same hashcode 【发布时间】:2013-04-30 07:47:14 【问题描述】:

Hashcode()和equals()的概念是

1) 如果两个对象根据 equal() 相等,则对这两个对象中的每一个调用 hashcode 方法应该会产生相同的 hashcode。

另一个是

2) 不要求如果两个对象根据equal()不相等,则对两个对象中的每一个调用hashcode方法都必须产生不同的值。

我尝试并理解了第一个,这是第一点的代码。

public class Test 
    public static void main(String[] args) 

        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        map.put(1, 11);
        map.put(4, 11);
        System.out.println(map.hashCode());
        Map<Integer, Integer> map1 = new HashMap<Integer, Integer>();
        map1.put(1, 11);
        map1.put(4, 11);
        System.out.println(map1.hashCode());
        if (map.equals(map1)) 
            System.out.println("equal ");
        
    

上述程序为两个不同的对象提供了相同的哈希码。

谁能用一个例子解释一下,根据 equals() 不相等的两个不同对象如何具有相同的哈希码。

【问题讨论】:

将可能的哈希码数量与可能的Longs 或Strings 的数量进行比较。 en.wikipedia.org/wiki/Pigeonhole_principle Example of ==, equals and hashcode in java的可能重复 点(1)和(2)的来源是什么? 【参考方案1】:

2) 不要求如果两个对象根据equal()是不相等,那么对两个对象中的每一个调用hashcode方法都必须产生不同的价值观。

根据散列函数,2 个不同的对象可以具有相同的散列码。但是,相同的 2 个对象在散列时必须产生相同的结果(除非有人使用随机数实现散列函数,在这种情况下它是无用的)

例如,如果我正在对整数进行哈希处理,而我的哈希函数只是 (n % 10),那么数字 17 和数字 27 将产生相同的结果。这并不意味着这些数字是相同的。

【讨论】:

【参考方案2】:

字符串示例(以下所有字符串的哈希码均为 0):

public static void main(String[] args) 
    List<String> list = Arrays.asList("pollinating sandboxes",
                                      "amusement & hemophilias",
                                      "schoolworks = perversive",
                                      "electrolysissweeteners.net",
                                      "constitutionalunstableness.net",
                                      "grinnerslaphappier.org",
                                      "BLEACHINGFEMININELY.NET",
                                      "WWW.BUMRACEGOERS.ORG",
                                      "WWW.RACCOONPRUDENTIALS.NET",
                                      "Microcomputers: the unredeemed lollipop...",
                                      "Incentively, my dear, I don't tessellate a derangement.",
                                      "A person who never yodelled an apology, never preened vocalizing transsexuals.");
    for (String s : list) 
        System.out.println(s.hashCode());
    

(从this post窃取)。

【讨论】:

【参考方案3】:

hashCode() 有 32 位可能的值。您的对象可以有更多的东西,因此您将拥有一些具有相同 hashCode 的对象,即您无法确保它们是唯一的。

这在有限大小的哈希集合中变得更糟。 HashMap 的最大容量为 1

注意:在 HotSpot JVM 上,默认的 Object.hashCode() 永远不会是负数,即只有 31 位,尽管我不知道为什么。

如果您想生成大量具有相同 hashCode 的对象,请查看 Long。

// from Long
public int hashCode() 
    return (int)(value ^ (value >>> 32));


for(long i = Integer.MIN_VALUE; i < Integer.MAX_VALUE;i++) 
    Long l = (i << 32) + i;
    System.out.print(l.hashCode()+" ");
    if (i % 100 == 0)
        System.out.println();

这将生成 40 亿个 Long 且 hashCode 为 0。

【讨论】:

如果你想生成很多具有相同hashCode的对象,重写“public int hashChode()”返回相同的hashCode不是更简单。这不是最终的。【参考方案4】:

如果您知道 HashMap 是如何实现的以及它的用途,我很难理解。 Hashmap 采用大量值,并将它们拆分为更小的集合(桶),以便更快地检索元素。基本上你只需要搜索一个桶而不是你的元素的完整列表。桶在一个数组中,其中索引是哈希码。每个桶包含一个具有相同哈希码但不等于()的元素的链接列表。我认为在 Java 8 中,当存储桶大小变大时,他们转而使用树形图。

【讨论】:

【参考方案5】:

相信会帮助你理解……

Java 对象的哈希码只是一个数字,它是 32 位有符号整数,它允许对象由基于哈希的数据结构管理。我们知道哈希码是JVM分配给一个对象的唯一ID号。但实际上,哈希码并不是一个对象的唯一编号。如果两个对象相等,那么这两个对象应该返回相同的哈希码。所以我们必须实现一个类的 hashcode() 方法,如果两个对象相等,即通过该类的 equal() 方法进行比较,那么这两个对象必须返回相同的哈希码。如果你要覆盖 hashCode,你还需要覆盖 equals 方法。

参考:https://www.java2novice.com/java_interview_questions/hashcode/

【讨论】:

【参考方案6】:

其实很简单,

首先我们必须知道哈希码是什么。

在 java 中,哈希码只是一个 32 位有符号整数,它以某种方式从相关数据中派生而来。整数类型通常只是 (Int Data) Mod(一些合理的大素数)。

让我们对整数做一个简单的散列。 定义:

public int hash(int num) return num % 19 ;  

在这种情况下,19 和 38 都会返回 0 的哈希值。

对于字符串类型,哈希值是从字符串中的单个字符和每个字符的位置得出的,除以一个相当大的数字。 (或者,在 Java 的情况下,忽略 32 位和的溢出)。

鉴于可能存在任意多个字符串,并且字符串的哈希码数量有限 (2^32),鸽子洞原理指出至少有两个不同的字符串会产生相同的哈希码。

【讨论】:

【参考方案7】:

hashCode 的目的是启用以下公理和推论:

如果碰巧知道两个对象的散列码,而这些散列码不匹配,则无需进一步检查对象即可知道对象不匹配。即使两个任意选择的不匹配对象有 10% 的机会具有匹配的哈希码,测试哈希码也可以消除 90% 的比较,否则会需要。没有消除 99.99% 那样大的胜利,但绝对值得。

知道一堆对象中没有一个对象具有特定的哈希码意味着该堆中的所有对象都不会匹配具有该哈希码的对象。如果将一组对象划分为散列码为偶数的对象和散列码为奇数的对象,并且想知道是否有给定的对象的散列码恰好为偶数,则无需检查任何内容在奇数散列项的集合中。同样,无需在偶数散列集合中寻找奇数散列项。因此,即使是二值散列也可以将搜索速度提高近一半。如果将集合划分为更小的分区,则可以进一步加快速度。

请注意,如果每个不同的项目返回不同的哈希值,hashCode() 将提供最大的好处,但即使许多项目具有相同的哈希值,它也可以提供实质性的好处。 90% 的节省和 99.99% 的节省之间的差异通常比数字所暗示的要大得多,因此如果一个人可以合理地轻松地将事情改进到 99%、99.9% 或更好的话,应该这样做,但他之间的区别错误匹配为零且集合中有一些错误匹配是非常轻微的。

【讨论】:

【参考方案8】:

Actullay,这个链接更清楚地解释了如果哈希码等于会发生什么。

http://www.javamadesoeasy.com/2015/02/hashmap-custom-implementation.html

【讨论】:

【参考方案9】:

我的理解是 hashCode 是内存地址的数字表示,但不是实际地址。可以更改,不影响实际地址。因此,应该可以将所有对象设置为相同的 hashCode,即使它们都是完全不同的东西。想想一个街区里的每个人都突然拥有相同的街道地址。他们是真正不同的人,但现在都共享相同的街道地址。他们的房子没有动,一个淘气的少年只是给每个人贴上了“100 N. Main”的标签。

我对 Java 还很陌生,所以请谨慎对待我的回复。

【讨论】:

这实际上是一个关于哈希码是什么的完全错误的想法。

以上是关于具有相同哈希码的两个不相等对象的主要内容,如果未能解决你的问题,请参考以下文章

Java HashCode

如果两个对象的哈希码相同则他们不一定相同,如果对象一致则哈希码一定相同

Java开发进阶知识之学习篇——hashCode和equals

在 java 对象中覆盖哈希码的目的是啥? [复制]

对象哈希码

我如何理解这句话“具有相同哈希值的两个实例不一定相等。”