85.源码分析

1.hashMap

参考:

HashMap中hash(Object key)原理,为什么(hashcode >>> 16) :http://www.fu-w.com/a/63569.html

1.1 结构

数据 + 链表 +红黑树

数组:一段连续控件存储数据,指定下标的查找,时间复杂度O(1),通过给定值查找,需要遍历数组,自已对比复杂度为O(n) 二分查找插值查找,复杂度为O(logn)
线性链表:增 删除仅处理结点,时间复杂度O(1)查找需要遍历也就是O(n)
二叉树:对一颗相对平衡的有序二叉树,对其进行插入,查找,删除,平均复杂度O(logn)
哈希表:哈希表中进行添加,删除,查找等操作,性能十分之高,不考虑哈希冲突的情况下,仅需一次定位即可完成,时间复杂度为O(1)哈希表的主干就是数组

1.1 为什么加载因子 设置为0.75

   当加载因子越大数组的利用率越高,但hash碰撞将越大,经计算 0.75 是一个理想值,数组利用率高 hash碰撞低

1.2 为什么链表长度大于8 转化为红黑树

  根据泊松定律,当链表长度为8的时候落入该index的概率1亿万分之一

1.3 红黑树 结构有什么好处

减少了时间复杂度: 链表平均复杂度O(n)    树结构平均复杂度O(logn)

1.4 为什么hash计算要 高低位进行异或运算  (h = key.hashCode()) ^ (h >>> 16)

目的: 让得到的下标更加散列

hashcode为四字节  所以 一共32(4*8) 位

平时用map大多数情况下map里面的数据不是很多。这里与(length-1)相&,但由于绝大多数情况下length一般都小于2^16即小于65536。所以return h & (length-1);结果始终是h的低16位与(length-1)进行&运算

为什么用^而不用&和| ???

因为&和|都会使得结果偏向0或者1 ,并不是均匀的概念,所以用^

补充: 与运算(&)、或运算(|)、异或运算(^)

   与运算(&):两个同时为1,结果为1,否则为0

  或运算(|):参加运算的两个对象,一个为1,其值为1。

  异或运算(^):参加运算的两个对象,如果两个位为“异”(值不同),则该位结果为1,否则为0

1.2 初始化大小

1.2.1 开发者没有设置初始值

1.2.2  开发这给出了初始值

若开发者给出的非2的幂次方,hashMap会将初始值设置位大于且最接近初始值的2的幂次方

1.2.3  为什么初始化要是2的幂次方???

1.在计算key值的index时候通过与运算(&)与取模方式结果相同,但是与运算效率高很多(计算机底层是2进制) 如图3

2.jdk 1.8的扩容时候对数据迁移用到了高低位,不需要再去rehash效率高了很多 如图4

文章分享完毕,希望我的分享对大家有所帮助。更多学习技巧也可参阅:网站源码、模板、教程

猜你喜欢

转载自www.cnblogs.com/meilideni/p/12977152.html