HashMap学习笔记:原理

1.hashmap的结构和底层原理?

  • 数组+链表:即在每一个数组里面存放了 key - value 的实例。
  • 本身所有位置都是为null,再put插入的时候会根据key的hash值去计算一个数组的index坐标位置

2.为什么需要链表,链表是怎么样的?

  • 数组的长度是有限的,再有限的长度内使用hash,会存在一定的相同概率,就形成了链表。

3.新得Entry节点是怎么插入链表中的?

  • jdk8之前是头插入法:新来的值会取代原有的值,原有的值顺推到链表中。即同一位置上的新元素总会被放在链表的头部
  • jdk8之后是尾插入法:即新来的元素总是放再链表的尾部

4.数组的容量是有限的,什么时候进行resize扩容呢?
有两个元素因子:

  • Capacity:hashmap当前长度
  • LoadFactor:负载因子,默认75%
    即当容量达到了负载因子规定的长度时,会进行resize扩容,例如:
    当前长度为100,插入第76个数据时便会进行resize。

5.如何进行扩容?

  1. 扩容:创建一个新的Entry空数组,长度为原来的2倍。
  2. rehash:遍历所有Entry数组,把所有的Entry重新hash到空数组中。

6.为什么需要重新hash?

  1. 当长度扩大以后,hash的规则会改变:
  2. hash的公式:index = HashCode(key)& (Length - 1)

7.jdk8为何要改成尾插入法?

  1. 比如当前的容量为2,分别插入A,B,C,假设 此时数据插入了还未进行扩容,那么扩容前,链表的指向是A->B->C。
    resize的复制方式:使用了单链表的头插入法,同一个位置的新元素总会被放在链表的头部位置。

  2. 在旧数组中同一个Entry链上的元素通过重新计算索引位置后,有可能会放到新数组的不同位置上,有可能造成的隐患:
    (1) 链表的指向本来应该是A->B->C,可能导致A->C,B计算到新数组中别的位置上了
    (2) resize的复制方式又是头插入法,A,B互相重新hash计算索引插入链表,便形成了链表成环。此时取值时,会发生死循环

  3. java8之后链表有红黑树,把原本O(n)的时间复杂度降低到了O(login)

  4. 头插法:会改变链表上的顺序;尾插法:在扩容是会保证链表元素原本的顺序,就不会形成链表成环

  5. jdk7在多线程中使用hashmap可能会导致死循环,原因就是扩容转移后前后链表顺序倒置,在转移过程中修改了原链表中的节点的引用关系

  6. jdk8扩容前后保持不变

8.jdk8是否可把hashmap用于多线程
hashmap源码并没有在put,get方法加同步锁,线程安全无法保证

9.hashmap的默认初始长度为什么是16?为什么不用别的?

  • 源码中:DEFAULT_INITIAL_CAPACITY = 1 << 4;
    位与运算 比 算数运算 效率高
  • 数组 index = HashCode(key)& (Length - 1),因为在不是2的幂的数字的时候,Length-1的值是所有二进制位全为1, 这种情况,index的结果等同于hashCode后几位的值。
  • 只要输入HashCode本身分布均匀,Hash算法的结果就是均匀的。为了实现均匀分布。

10.为什么重写equals方法的时候要重写hashCode方法?
java中所有的对象都继承于Object类,Object类中有两个方法equals、hashCode,这两个方法都是用来比较两对象是否相同。

在未重写equals时,equals比较的是两个对象的地址

对于值对象,==比较的是两个对象的值
对于引用对象,比较的是两个对象的地址

hashmap是通过key的hashCode去寻找index的,比如key分别为A,B,它们在同一个链表上,通过hash计算的到它们的index是相同的。此时怎么才能得到他们对于具体的值呢?equals,因此在重写equals时一定要重写hashCode方法.

11.如何处理hashmap线程安全?
使用HashTable、CurrentHashMap。

HashTable:直接在方法上锁( synchronized ),并发度很低
CurrentHashMap:单独发表一文叙述

12.hashmap是如何解决hash碰撞的?
hash计算出hashCode,相同的hashCode会存储在同一个bucket(哈希桶)中。
使用链表解决的了碰撞问题,当发生碰撞时,对象会存储在链表的下一个节点中。每个链表节点都存储键值对象,当两个不通的键有相同的hashCode时,会通过键对象的equals()来找到具体的值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值