根据这个问题
how-does-a-hashmap-work-in-java和this
许多键值对可以存放在同一个存储桶中(在使用哈希计算存储桶的索引之后),当我们调用get(key)
时,它会查看链接列表并使用{{1}进行测试方法。
对我来说听起来并不是真的优化,在使用equals
之前是不是要比较链接列表的hashCode
?
如果答案为否:
这意味着大多数时间桶只包含1个节点,你能解释一下原因吗?因为根据this logical explanation,许多不同的键可以具有相同的桶索引。
如何实现确保密钥的良好分配?这可能意味着存储桶表大小相对于键数
即使表Bucket大小等于键的数量,HashMap equals
函数如何确保键的良好分配?不是随机分布?,
答案 0 :(得分:6)
实施是开源的,所以我鼓励您read the code提出任何具体问题。但这是一般的想法:
hashCode()
方法分布不正确(例如,return 0;
)然后HashMap将表现不佳。HashMap::hash
)get
方面,对存储桶中的每个元素进行了几次检查(是的,实现为链接列表)
put
时被缓存。这样可以防止具有不同hashCodes的元素(因此通过hashCode的契约和由Object
建立的等号不相等)但恰好属于同一个桶(请记住,桶索引基本上是hashCode % buckets.length
) equals
以确保它们真的相等。请记住,相等意味着相同的hashCode,但是相同的hashCode 不需要相等(并且不能,因为某些类可能具有无限数量的不同值 - 如String
- 但是只有有限数量的可能的hashCode值)对hashCode和equals进行双重检查的原因是快速和正确。考虑两个具有不同hashCode的键,但最终位于相同的HashMap存储桶中。例如,如果密钥A具有hashCode = 7并且B具有hashCode = 14,并且存在7个桶,则它们都将在桶0(7 % 7 == 0
和14 % 7 == 0
)中结束。检查hashCodes有一种快速查看A和B不相等的方法。如果您发现hashCodes相等,那么您可以通过调用equals
来确保它不仅仅是hashCode冲突。这只是一个优化,真的;一般的哈希映射算法不需要它。
答案 1 :(得分:1)
为了避免在链表中进行多重比较,HashMap中的桶数通常保持足够大,以至于大多数桶只包含一个项目。默认情况下,java.util.HashMap会尝试维护足够的存储区,以使项目数仅为存储区数量的75%。
某些存储桶可能仍然包含多个项目 - 所谓的“哈希冲突” - 其他存储桶将为空。但平均而言,大多数包含项目的桶只包含一个项目。
equals()方法将始终至少使用一次,以确定密钥是否完全匹配。请注意,equals()方法通常至少与hashCode()方法一样快。
良好的hashCode()实现维护了良好的密钥分发; HashMap对此没什么影响。一个好的hashCode()方法是返回的哈希与对象的值尽可能随机关系的方法。
对于错误哈希函数的示例,曾几何时,String.hashCode()方法仅依赖于字符串的开头。问题在于,有时您希望在HashMap中存储一堆字符串,这些字符串都是相同的 - 例如,单个网站上所有页面的URL - 导致哈希冲突的比例过高。我相信String.hashCode()后来被修改以解决这个问题。
答案 2 :(得分:0)
dosn它比较链接列表的hachCodes而不是使用 等于
不需要。 hashcode用于确定放置或获取操作的桶号。一旦你知道带有哈希码的桶号并在那里找到它的链表,那么你知道你需要迭代它并需要检查相等性以找到确切的密钥。所以这里不需要哈希码比较
这就是为什么hashcode应该尽可能唯一,以便最好地进行查找。
这意味着大多数时间桶只包含1个节点
不。它取决于hascode的唯一性。如果两个密钥对象具有相同的哈希码但不相等,则桶包含两个节点
答案 3 :(得分:0)
当我们将Key和Value对象传递给Java HashMap上的put()方法时,HashMap实现调用Key对象上的hashCode方法,并将返回的hashcode应用到自己的散列函数中,以找到存储Entry对象的存储桶位置,重要的一点是提及是Java中的HashMap将key和value对象存储在存储桶中Map.Entry
,这对理解检索逻辑至关重要。
在检索Key的值时,如果hashcode与其他一些键相同,则bucket位置相同,并且HashMap中会发生冲突,因为HashMap使用LinkedList来存储对象,此条目(Map.Entry的对象包含键)和值)将存储在LinkedList中。
密钥的良好分配将取决于hashcode
方法的实施。此实现必须遵守哈希码的一般合同:
答案 4 :(得分:0)
您可以访问此git-hub存储库“https://github.com/devashish234073/alternate-hash-map-implementation-Java/blob/master/README.md”。
您可以通过基本实现和示例了解HashMap的工作原理。 ReadMe.md解释了所有。
在此处包含示例的某些部分:
假设我必须存储以下键值对。 (KEY1,VAL1) (KEY2,val2)将 (KEY3,VAL3) (....,....) (key99999,val99999)
让我们的哈希算法仅在0到5之间产生值。
首先,我们创建一个带有6个桶的机架,编号为0到5。
存储:
存储(keyN,valN):
1.getget'keyN'的哈希值
2.ssuppose我们得到2
3.将(keyN,valN)存储在机架2中
搜索:
搜索keyN:
1.get hash of keyN
2.lets说我们得到2
3.我们遍历机架2并获取密钥并返回值
因此,对于N个键,如果我们将它们线性存储,则需要N比较来搜索最后一个元素,但是对于其哈希算法生成25个值的hashmap,我们只需要进行N / 25比较。 [哈希值均匀分散]