hashmap简单描述


JDK1.7

  1. 数据结构:  数组+链表

  2. put过程中发生hash碰撞是如何处理的?

    答: 使用 “头插法” :将 新数据 插入当前数组,数组中 原数据 向 链表下(纵向)移动

  3. “头插法” 出现的问题?

    答1: 如果一直发生hash碰撞,那么链表就会向下无限的增加下去,链表会变的很长。

       众所周知,链表的特点是:增删快,查询慢。若果链表很长,那么查询就更慢了。

    答2:在多线程的情况下,同一索引位置的节点在扩容后 链表会变成环状 ,导致出现死循环的情况。

  4.什么是hash碰撞?

    答: 两个不同的值(如:张三 、李四),经过hash计算后,得到相同的hash值,后来李四要放到原来张三的位置,但是数组的位置已经被张三占用了,导致的冲突。

JDK1.8

  1. 数据结构: 数组+链表+红黑树

    

  2. put 过程中发生 hash碰撞是如何处理的?

    答: 使用 “尾插法” : 将 新数据 插入当前链表的尾部,使其成为当前链表尾节点。

  3. “尾插法” 解决的问题

    答: 解决“头插法”处出现的死循环

  4. 为什么使用“红黑树”?

    答: 主要是为了提升在hash冲突时(链表过长)的查找性能,使用链表查找性能是O(n) ,使用红黑树查找性能是O(logn) , 提高了查询效率

  5. 什么时候 链表 转 红黑树?

    答:当 链表 长度 大于等于 8 时,由 链表 转成 红黑树

  6. 什么时候 红黑树 转 链表?

    答:当 红黑树上节点数小于等于6时,由 红黑树 转成 链表

  7.  hashmap 什么时候进行扩容 (数组空间不够,需要进行扩容) ?

    答:  数组的默认长度是 :16             扩容因子是 :0.75

       16 * 0.75=12    数组长度使用到12的时候开始扩容

  8. hashmap 是如何扩容的?

    答: 底层是 数组,那么数组是如何扩容的呢?

      寻找一个长度是原数组2倍的新数组进行扩容。

    为什么数组扩容是2倍呢?

      2倍满足,扩容一定的 2的次方 默认要求 ,

      满足这个条件 有利于 计算生成的 hash值 放到hashmap数组中的值(value)更加均匀。

  9. hashmap的put(添加)方法流程

    答: 1. 调用put() 方法   -->底层 调用hashmap类的putval() 方法

       2. 首先 根据 key 进行hash运算 

       用 key 的 hashCode  与 key的hashcode 右移16位做 异或运算

      3.然后 

  10. 为什么要做hash运算?

     答:查看源码可以看出,通过key计算出 hash值是为了后续key和value放入数组中的位置

        hash值与数组的长度进行计算,放到对应的数组中

        存放到数组中的位置 = key计算出hash值 & n  ( hash值 % 数组的长度(16) = 下标 )

  11. hashmap的重要属性以及有哪些作用?

     答:  <1>  size:hashmap已经存储的节点数

         <2> threshold:扩容阈值,当hashmap的个数达到该值,触发扩容

         <3> loadFactor:负载因子,扩容阈值=容量*负载因子

  12.

 总结JDK1.8有哪些优化?

   1. 数据结构:

     由“数组+链表” 改成 “数组+链表+红黑树”,主要是优化hash冲突严重时,链表过长的查找性能

  2. 扩容:

     由“头插法” 改成 “尾插法”,避免了并发下的死循环

  3. hsah计算:

    1.8只是简单的进行高16位参与运算

   4. 其他:

    目前还不太清楚

结束语:

  好了,目前小编的技术能力就到这里了,其他问题正在努力学习中......