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

Hashcode()和equals()的概念是

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

而另一个是

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

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

public class Test { public static void main(String[] args) { Map map = new HashMap(); map.put(1, 11); map.put(4, 11); System.out.println(map.hashCode()); Map map1 = new HashMap(); map1.put(1, 11); map1.put(4, 11); System.out.println(map1.hashCode()); if (map.equals(map1)) { System.out.println("equal "); } } } 

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

有人可以用一个例子来解释我,根据equals()不同的两个不同对象如何具有相同的哈希码。

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

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

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

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

 public static void main(String[] args) { List 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()); } } 

(从这篇文章中偷来的 )。

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。

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

  • 如果碰巧知道两个对象的哈希码,并且那些哈希码不匹配,则无需再费心检查对象以了解对象将不匹配。 即使两个任意选择的非匹配对象有10%的机会具有匹配的哈希码,测试哈希码也可以消除90%的比较。 没有像消除99.99%那么大的胜利,但绝对值得。

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

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

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

实际上很简单,

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

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

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

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

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

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

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

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

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

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

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