Java SE 052 HashSet与HashMap源代码深度剖析

(1)一个人只要自己不放弃自己,整个世界也不会放弃你.
(2)天生我才必有大用
(3)不能忍受学习之苦就一定要忍受生活之苦,这是多么痛苦而深刻的领悟.
(4)做难事必有所得
(5)精神乃真正的刀锋
(6)战胜对手有两次,第一次在内心中.
(7)编写实属不易,若喜欢或者对你有帮助记得点赞+关注或者收藏哦~

Java SE 052 HashSet与HashMap源代码深度剖析

1.HashSet底层源码分析

1.1.HashSet底层是使用HashMap实现的。

1.2.HashSet是如何用的HashMap

解说:
  (1)当我们将一个元素放置到Set当中的时候,它实际上是将元素作为底层所维护的那个Map的key,而value都是同一个对象。

  (2)当使用add方法将对象添加到Set当中时,实际上是将该对象作为底层所维护的Map对象的key,而value则者同一个Object对象(该对象我们用不上。)

  (3)HashMap在构造的时候,通常会先生成一个长度为16的Entry类型的数组。

1.3.Hash表的概念

  (1)当将一个对象放到数组里面当中时,会通过hash函数与要放置的对象做一次运算,这个运算之后会得到一个位置,这个位置就作为应该放置到数组当中的位置。

  (2)如果要查找这个元素的位置,也可以通过hash(散列)函数,再进行一次运算,就会直接定位到要找元素的位置,但是会存在一种冲突情况,我的一个位置上已经有元素了,我再去添加元素的时候,可能正好计算又是这个位置上,因为有元素了,就没办法往里边儿放了,所以它会提供一个函数再散列,重新的再去计算一下地址。即通知再散列的计算方式将元素放到新的位置。如果再散列又发现该位置又有新元素了,它就不会再重新计算了,它就认为这个数组的元素快满了,这时候它就会开辟一个新的数组,并且将原来数组当中的元素通过散列放到新的数组里面。这时数组空闲空间就增大一些了,再去往里面放元素,发生冲突的情况概率就降低了。这种发生冲突术语叫做碰撞。什么时候我们认为数组快满了呢,是由default_load_factor(负载茵子来准定的)。即它认为当数组里边儿75%的位置上已经被占据了元素,数组就已经满了。就会开辟一个新的数组。

  (3)default_initial_capacity:表示初始的数组的长度。即生成一个长度为16的Entry类型的数组。那么我们的对象放在哪儿呢,是放在数组里面的。即HashMap最底层显然是用一个数组去实现的。HashSet底层是HashMap,HashMap底层是数组.

1.4 HashMap底层

  HashMap底层维护一个数组,我们向HashMap中所放置的对象实际上是存储在该数组当中.

1.5.Entry<k,v>内容

  HashMap底层维护的Entry类型的数组,每个元素都是一个Entry类型的,每个Entry类型里面负责维护的是一个key的信息和一个value的信息。除了这两个以外,还有一个Entry<K,V> next这样一个引用,这个引用是一个Entry<K,V>类型的一个引用.

在这里插入图片描述

1.6.Map对象

  (1)底层确实是一个数组,每一个数组元素类型都是一个Entry类型.

  (2)每一个Entry类型又是由一个链表的结构不断的往下链,而每一个Entry里面,是往Map里面增加的key的信息和Value的信息,它是通过这种方式去实现的。数组加上链表这样一种混合的结构。

  (3)这么多集合归根到底还是通过数组来完成的。因为只有数组才能维护一些对象。其它的东西都维护不了。不管这个结构操作起来有多么复杂,多么简单,底层无外乎就这两种方式。

1.7.总结

  (1)当向HashMap中put一对键值时,它会根据key的hashCode值计算出一个位置,该位置就是此对象准备往数组中存放的位置。

  (2)如果此位置没有对象存在,就将此对象直接放进数组当中;如果该位置已经有对象存在了,则顺着此存在的对象的链开始寻找(Entry类有一个Entry类型的next成员变量,指向了该对象的下一个对象),如果此链上有对象的话,再去使用equals方法进行比较,如果对此链上的某个对象的equals方法比较为false,则将该对象放到数组当中,然后将数组该位置以前存在的那个对象链接到此对象的后面。

1.8.HashMap的内存实现布局图:

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/xiogjie_67/article/details/108540933