根据我的理解,我认为:
两个对象具有相同的hashcode是完全合法的。 如果两个对象相等(使用equals()方法),则它们具有相同的hashcode。 如果两个对象不相等,那么它们就不能有相同的hashcode
我说的对吗?
如果我没猜错的话,我有以下问题: HashMap在内部使用对象的hashcode。那么,如果两个对象可以具有相同的hashcode,那么HashMap如何跟踪它使用的键呢?
有人能解释一下HashMap内部是如何使用对象的hashcode的吗?
根据我的理解,我认为:
两个对象具有相同的hashcode是完全合法的。 如果两个对象相等(使用equals()方法),则它们具有相同的hashcode。 如果两个对象不相等,那么它们就不能有相同的hashcode
我说的对吗?
如果我没猜错的话,我有以下问题: HashMap在内部使用对象的hashcode。那么,如果两个对象可以具有相同的hashcode,那么HashMap如何跟踪它使用的键呢?
有人能解释一下HashMap内部是如何使用对象的hashcode的吗?
当前回答
你可以在http://javarevisited.blogspot.com/2011/02/how-hashmap-works-in-java.html上找到很好的信息
总结:
HashMap的工作原理是哈希
put(key, value): HashMap将key和value对象都存储为Map.Entry。Hashmap应用hashcode(key)来获取桶。如果有碰撞,HashMap使用LinkedList存储对象。
get(key): HashMap使用key Object的hashcode来查找桶的位置,然后调用keys.equals()方法来识别LinkedList中的正确节点,并在Java HashMap中返回该键的相关值对象。
其他回答
你的第三个断言是不正确的。
两个不相等的对象拥有相同的哈希码是完全合法的。它被HashMap用作“第一遍过滤器”,以便映射可以快速找到具有指定键的可能条目。然后测试具有相同哈希码的键是否与指定的键相等。
您不会希望要求两个不相等的对象不能具有相同的哈希码,否则将限制为232个可能的对象。(这也意味着不同类型甚至不能使用对象的字段来生成哈希码,因为其他类可以生成相同的哈希码。)
这将是一个很长的答案,拿着饮料继续阅读…
哈希就是在内存中存储一个键-值对,可以更快地读写。它将键存储在数组中,值存储在LinkedList中。
假设我想存储4个键值对
{
“girl” => “ahhan” ,
“misused” => “Manmohan Singh” ,
“horsemints” => “guess what”,
“no” => “way”
}
为了存储键,我们需要一个4元素的数组。现在我如何将这4个键中的一个映射到4个数组索引(0,1,2,3)呢?
因此java找到单个键的hashCode并将它们映射到特定的数组索引。 哈希码公式是-
1) reverse the string.
2) keep on multiplying ascii of each character with increasing power of 31 . then add the components .
3) So hashCode() of girl would be –(ascii values of l,r,i,g are 108, 114, 105 and 103) .
e.g. girl = 108 * 31^0 + 114 * 31^1 + 105 * 31^2 + 103 * 31^3 = 3173020
哈希和女孩!!我知道你在想什么。你对狂野二重唱的迷恋可能会让你错过一件重要的事情。
为什么java要把它乘以31 ?
因为,31是奇数质数形式为2^5 - 1。奇素数降低了哈希碰撞的概率
这个哈希码是如何映射到数组下标的呢?
答案是,哈希码%(数组长度-1)。在我们的例子中,“girl”被映射为(3173020 % 3)= 1。它是数组的第二个元素。
值“ahhan”存储在与数组索引1相关的LinkedList中。
HashCollision -如果您尝试使用上面描述的公式查找密钥“误用”和“horsemints”的hasHCode,您将看到两者都给出相同的1069518484。Whooaa ! !〇教训
2个相等的对象必须具有相同的hashCode,但如果没有保证 hashCode匹配,则对象相等。所以它应该存储 这两个值都对应于1号桶的“误用”和“horsemints” (1069518484% 3)。
现在哈希图看起来是-
Array Index 0 –
Array Index 1 - LinkedIst (“ahhan” , “Manmohan Singh” , “guess what”)
Array Index 2 – LinkedList (“way”)
Array Index 3 –
现在,如果有人试图找到键“horsemints”的值,java很快就会找到它的hashCode,对它进行模块化,并开始在LinkedList对应的索引1中搜索它的值。因此,这样我们就不需要搜索所有的4个数组索引,从而使数据访问更快。
但是,等一下。有3个值在那个linkedList对应的数组索引1,它如何找出哪一个是值为关键“horsemints”?
其实我撒谎了,我说HashMap只是在LinkedList中存储值。
它将两个键值对存储为映射条目。实际上Map是这样的。
Array Index 0 –
Array Index 1 - LinkedIst (<”girl” => “ahhan”> , <” misused” => “Manmohan Singh”> , <”horsemints” => “guess what”>)
Array Index 2 – LinkedList (<”no” => “way”>)
Array Index 3 –
现在你可以看到,当遍历对应于ArrayIndex1的linkedList时,它实际上会将linkedList的每个条目的key与horsemints进行比较,当它找到一个时,它会返回它的值。
希望你读得开心:)
你在第三点上错了。两个条目可以具有相同的哈希码,但不相等。看一下HashMap的实现。从OpenJdk中获取。你可以看到它检查哈希值是否相等键值是否相等。如果第三点成立,那么检查键值是否相等就没有必要了。哈希码在键之前进行比较,因为前者是更有效的比较。
如果您有兴趣进一步了解这方面的知识,请参阅Wikipedia关于开放寻址冲突解决的文章,我认为这是OpenJdk实现使用的机制。这种机制与另一个答案中提到的“桶”方法略有不同。
你可以在http://javarevisited.blogspot.com/2011/02/how-hashmap-works-in-java.html上找到很好的信息
总结:
HashMap的工作原理是哈希
put(key, value): HashMap将key和value对象都存储为Map.Entry。Hashmap应用hashcode(key)来获取桶。如果有碰撞,HashMap使用LinkedList存储对象。
get(key): HashMap使用key Object的hashcode来查找桶的位置,然后调用keys.equals()方法来识别LinkedList中的正确节点,并在Java HashMap中返回该键的相关值对象。
HashMap是一个Entry对象数组。
把HashMap看作是一个对象数组。
看看这个对象是什么:
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry<K,V> next;
final int hash;
…
}
每个Entry对象表示一个键值对。如果一个桶有多个Entry,下一个字段引用另一个Entry对象。
有时候,两个不同对象的哈希码可能是相同的。在这种情况下,两个对象将保存在一个bucket中,并将显示为链表。 入口点是最近添加的对象。该对象引用具有下一个字段的另一个对象,以此类推。最后一项指向null。
当使用默认构造函数创建HashMap时
HashMap hashMap = new HashMap();
数组的大小为16,默认负载平衡为0.75。
添加新的键-值对
计算键的hashcode 计算元素应该放置的位置哈希% (arrayLength-1)(桶号) 如果你试图用一个已经保存在HashMap中的键添加一个值,那么值将被覆盖。 否则元素被添加到桶中。
如果存储桶已经有至少一个元素,则添加一个新元素并将其放置在存储桶的第一个位置。它的下一个字段指向旧元素。
删除
计算给定键的hashcode 计算桶号哈希% (arrayLength-1) 获取桶中第一个Entry对象的引用,并通过equals方法遍历给定桶中的所有条目。最终我们会找到正确的入口。 如果没有找到所需的元素,则返回null