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

问题描述 投票:15回答:8

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()不同的两个不同对象如何具有相同的哈希码。

java hashmap equals hashcode
8个回答
25
投票

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

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

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


7
投票

使用字符串的示例(以下所有字符串的哈希码均为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偷来的)。


6
投票

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

这在有限大小的哈希集合中变得更糟。 HashMap的最大容量为1 << 30或大约10亿。这意味着实际上只使用了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
投票

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


1
投票

hashCode的目的是实现以下公理和推论:

  • 如果有人碰巧知道两个对象的哈希码,并且那些哈希码不匹配,则无需进一步检查对象以了解对象将不匹配。即使两个任意选择的非匹配对象有10%的机会具有匹配的哈希码,测试哈希码也可以消除90%的比较。没有像消除99.99%那么大的胜利,但绝对值得。
  • 知道一堆中的任何对象都没有特定的哈希代码,这意味着该组中的任何对象都不会将该对象与该哈希代码匹配。如果将对象集合划分为哈希代码为偶数的对象和哈希值为奇数的对象,并且想要查找是否有一个哈希代码恰好是偶数的给定项目,则无需检查任何对象在奇数哈希项的集合中。同样,不需要在even-hash集合中查找奇数哈希项。因此,即使是双值哈希也可以将搜索速度提高近一半。如果将集合划分为较小的分区,则可以进一步加快速度。

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


0
投票

实际上很简单,

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

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

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

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

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

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

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


0
投票

实际上,这个链接解释了如果hashcode等于更清楚会发生什么。

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


0
投票

我相信它会帮助你理解......

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

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


-1
投票

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

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

© www.soinside.com 2019 - 2024. All rights reserved.