八股02 HashMap

HashMap存储数据的方式:​​​​​​​

jdk1.8之前,HashMap底层通过数组 + 链表,java8及之后通过数组 + 链表/红黑树 实现,通过计算key的哈希值,找到元素存储的位置,jdk1.7之后通过  ( n - 1) & hash 来计算元素在数组中的存储位置,并且hash值是经过一定扰动的,减少冲突。存入元素时,如果目标位置上已经有了元素,会判断key是否相等,相等就直接覆盖,不相等就向后插入,链表长度大于8就会将链表转为红黑树,提升查询性能,小于6就会再转为链表,降低维护成本。

负载因子:

默认为0.75,用于判断是否需要扩容,如果size > 负载因子 * Capacity ,就扩容为原来的两倍

负载因子过高,会导致hash冲突更频繁,导致性能下降

过低会导致内存空间的浪费

如果已知需要多大的空间(n),可以将HashMap容量初始化为  n / 负载因子 + 1, + 1 主要是为了防止向下取整,导致容量不够

hashCode 与equals方法

规范:如果两个对象,使用equals判断为true,那么他们的hashCode值必须相等

hashCode用于计算key的hash值,确定元素的存储位置

equals方法,用于判断两个key是否相同

为什么要重写hashCode和equals方法,

不重写equals方法的话,会使用从父继承过来的equals方法,没有显式的使用extends 的话,用的就是Object类的equals方法,也就是单纯的比较对象的地址是否相同,但一般要根据实际业务来判断是否相同

为什么要重写hashCode

前面说过hashCode使用来计算对象存储位置的,没有重写的话,默认是计算对象地址的hash值,这就可能导致,我们逻辑上认为相同的元素,被存在了不同的桶中

为什么HashMap扩容时使用2 的m次方倍?

  当n为2的m次方倍时,(n - 1) & hash == hash % n,而%运算很慢,始终确保HashMap的Capacity 为2的m次方倍,可以用这个属性来提高计算速度,并且可以让元素分布更均匀 2^n - 1后的二进制表现形式,后n 位都是1,相比于有0的情况,元素分布更均匀

  

使用HashMap提升性能的技巧:

1. 前面说过的,如果已知需要的空间,可以计算 初始化多大容量,能刚好保证不扩容

2. 根据实际业务,调整负载因子

3. 确保hashCode分布均匀

TreeMap (用的比较少)

通过红黑树实现,插入,查找,删除都需要logn的时间复杂度

另外HashMap线程不安全,不要在多线程共享的场景下使用,HashTable虽是线程安全的,但是性能堪忧,HashTable是通过锁全表来保证线程安全的,唯一优点,锁的成本低。可以使用ConcurrentHashMap,

ConcurrentHashMap

java7 采用分段锁,将整个hashmap分为多个Segment,每一个Segment单独内共用这一个锁,一定程度上提高了性能

java8 采用CAS + synchronized桶锁,相较于java7的锁单个segment,粒度更细

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值