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

时间:2013-05-06 14:17:32

标签: java hashmap equals hashcode

Hashcode()和equals()概念是

  

1)如果两个对象根据equal()相等,那么在这两个对象中的每一个上调用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()的两个不同的对象如何具有相同的哈希码。

9 个答案:

答案 0 :(得分:25)

  

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

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

例如,如果我正在散列整数并且我的散列函数只是(n % 10),那么数字17和数字27将产生相同的结果。这并不意味着这些数字是相同的。

答案 1 :(得分:6)

hashCode()具有32位可能的值。你的对象可以有更多,所以你将有一些具有相同hashCode的对象,即你不能确保它们是唯一的。

这在有限大小的哈希集合中变得更糟。 HashMap的最大容量是1 <&lt;&lt; 30或约十亿。这意味着实际上只使用了30位,如果你的集合不使用16+ GB并且只说一千个桶(或技术上1 <10),那么你真的只有1000个桶。

注意:在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。

答案 2 :(得分:6)

使用字符串的示例(以下所有字符串的哈希码均为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 :(得分:2)

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

答案 4 :(得分:1)

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

  • 如果有人碰巧知道两个对象的哈希码,并且这些哈希码不匹配,则无需进一步检查对象就知道对象不匹配。即使两个任意选择的非匹配对象有10%的机会具有匹配的哈希码,测试哈希码也可以消除90%的比较。不如消除99.99%那么大,但绝对值得。

  • 知道一堆中的任何对象都没有特定的哈希码,这意味着该群中的任何对象都不会与具有该哈希码的对象匹配。如果将对象集合划分为哈希代码为偶数的对象和哈希为奇数的对象,并且想要查找是否有一个哈希代码恰好是偶数的给定项目,则无需检查任何对象在奇数哈希项的集合中。同样,不需要在even-hash集合中查找奇数哈希项。因此,即使是双值哈希也可以将搜索速度提高近一半。如果将一个集合划分为较小的分区,可以进一步加快速度。

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

答案 5 :(得分:0)

实际上很简单,

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

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

让我们对整数做一个简单的哈希 定义:

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

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

对于字符串类型,散列是从单个字符和字符串中的每个位置派生的,除以相当大的数字。 (或者,在Java的情况下,忽略32位总和的溢出)。

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

答案 6 :(得分:0)

Actullay,此链接解释了如果hashcode等于更清楚会发生什么。

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

答案 7 :(得分:0)

我相信它将帮助您了解...

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

ref:https://www.java2novice.com/java_interview_questions/hashcode/

答案 8 :(得分:-1)

我的理解是hashCode是内存地址的数字表示,但不是实际地址。它可以更改,而不会影响实际地址。因此,应该可以将所有对象设置为相同的hashCode,即使它们都是完全不同的东西。想想一个街区的所有人都突然拥有相同的街道地址。他们是真正不同的人,但现在所有人都拥有相同的街道地址。他们的房子没有移动,一个误入歧途的青少年只是将每个人称为“100 N. Main”。

我对Java很新,所以请谨慎对待我的回复。