HashMap了解一下

今天跟着Java3y的博客(http://www.zhongfucheng.bitcron.com/post/shou-ji/pcduan-wen-zhang-dao-hang)看了一下map接口以及其下子类的代码,水平有限,看的晕晕乎乎的,有的看不懂的地方暂时跳过了,先把理解的地方记录一下,好记性不如烂笔头头头头头。

依然盗图预警,本博客仅用于记录和学习,如有侵犯,请联系我。

HashMap不走心的介绍

  •  首先就是继承关系:HashMap继承AbstractMap类同时实现Map接口
  • 然后要理解一下hashmap的结构,hashmap底层结构是散列表+红黑树(红黑树的理解可以参考其他的优质博文:https://blog.csdn.net/chen_zhang_yu/article/details/52415077),至于散列表的实现,hashmap是采用数组+链表的方式,其中数组中的每个元素也就是平常说的桶,而使用链表主要是为了解决哈希冲突的问题。(大概结构如下图所示)

  • 下面来看一下HashMap的属性:

  • 然后是HashMap的构造方法,HashMap有四个构造函数,值得注意的是,即使在构造函数中指定了initcapacity,初始后的容量也不一定就是所指定的值。而是会返回一个大于指定值的且最接近的2的整数次幂。

  • put方法,以及put方法调用的putVal方法,在putVal方法中,初始时会调用resize方法初始化,当插入元素后会如果size大于阈值的大小,也需要调用resize方法进行再散列,但是。。e..这个方法目前对我来说看着比较困难,先总览一下,随后再补充吧。

  • get方法和remove方法,两者的逻辑差不多,以get方法为例,get中调用的是getNode方法,getNode方法中首先要保证key的哈希值是在散列表上的,然后看是否在桶上,如果在桶上则直接返回,否则利用链表或者红黑树进行搜索并返回(删除)

hashmap补充

 问题1:hashmap容量为什么是2的幂次

  以下答案摘自(https://blog.csdn.net/dam454450872/article/details/80376661)

  1. 首先length为2的整数次幂的话,h&(length-1)就相当于对length取模,这样便保证了散列的均匀,同时也提升了效率;(参考putVal方法中的使用)
  2. 若length为偶数,则最后一位为0,减去1后,最后一位一定为1,此时与h做位与运算,可能为奇数,也可能为偶数。可以反过来想对比一下,如果length为奇数,减一后最后 一位为0,与h做位与后,最后一位为0,一定为偶数,这样不能保证散列的均匀性

问题2:hashmap什么时候扩容

  以下答案摘自(https://blog.csdn.net/u011328417/article/details/80728571)

  1. 我们都知道hashmap的阈值为容量×装载因子。当元素个数大于阈值时就会触发一次扩容
  2. hashmap中定义了TREEIFY_THRESHOLD默认值为8,即当桶内链表的长度大于8时,为了保证效率,会转化为红黑树结构,但是红黑树是治标不治本的,即只能解决查找效率问题,不能解决冲突问题。另外,hashmap还定义了一个MIN_TREEIFY_CAPACITY默认值为64,当桶中的bin被树化时最小的hash表容量。也就是说为当桶数组元素大于 64,且桶内链表长度大于8时才将桶内链表转化为树形结构。所以,当桶内链表需要转化为红黑树前会先判断桶数组容量是否超过64,若未超过则先进行桶容量扩容。

  总结如下:

    当哈希表中的容量大于MIN_TREEIFY_CAPACITY时,表中的桶才能进行树形化
    否则桶内元素太多时会扩容,而不是树形化
    为了避免进行扩容、树形化选择的冲突,MIN_TREEIFY_CAPACITY值不能小于 4 * TREEIFY_THRESHOLD

猜你喜欢

转载自www.cnblogs.com/April1995/p/9550024.html