HashMap理解

1.由数组+链表的结构改为数组+链表+红⿊树。
2. 优化了⾼位运算的hash算法:h^(h>>>16)
3. 扩容后,元素要么是在原位置,要么是在原位置再移动2次幂的位置,且链表顺序不变。【当超过限制的时候会resize,然而又因为我们使用的是2次幂的扩展(指长度扩为原来2倍),所以,元素的位置要么是在原位置,要么是在原位置再移动2次幂的位置

1. 底层数据结构?

JDK 1.7 : Table数组+ Entry链表

JDK1.8 : Table数组+ Entry链表/红黑树

数组里面每个地方都存了Key-Value这样的实例,在Java7叫Entry在Java8中叫Node

2. 链表如何插入?

java8之前是头插法

在java8之后,都是所用尾部插入了 

JDK 1.7 采用头插法来添加链表元素,存在链表成环的问题,1.8 中做了优化,采用尾插法来添加链表元素

【核心还是因为头插会改变顺序】

3. 核心变量?什么时候扩容?什么时候链表树化?

DEFAULT_INITIAL_CAPACITY:Table数组的初始化长度16

MAXIMUM_CAPACITY:Table数组的最大长度

DEFAULT_LOAD_FACTOR:当元素的总个数>当前数组的长度 * 负载因子。2倍扩容

TREEIFY_THRESHOLD:链表树化阙值: 默认值为 8【将链表转红黑树】

UNTREEIFY_THRESHOLD:红黑树链化阙值: 默认值为 6

MIN_TREEIFY_CAPACITY:64 最小树化阈值,当Table所有元素超过改值,才会进行树化

4. 具体如何扩容?

  • 扩容:创建一个新的Entry空数组,长度是原数组的2倍。
  • ReHash:遍历原Entry数组,把所有的Entry重新Hash到新数组

为什么需要重新Hash?

index = hash(Key) & (Length - 1) 

其中:hash

    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

 高16bit不变,低16bit和高16bit做了一个异或?

为了减少碰撞。

5. 为什么要使用数组?使用其他结构是否可行?

 是否可以使用LinkedList代替数组结构?

List<Entry> table=new LinkedList<Entry>();

当然可以啊。

因为数组的效率最高。定位位置是通过hash&(length-1) .而LinkedList底层是链表

使用ArrayList是否可行?因为使用基本数组扩容可以自定义。HashMap中数组扩容刚好是2的次幂,在做取模运算的效率⾼

⽽ArrayList的扩容机制是1.5倍扩容

6. resize

7. 线程

在多线程使用场景中,应该尽量避免使用线程不安全的HashMap,而使用线程安全的ConcurrentHashMap

1.在JDK1.7中,当并发执行扩容操作时会造成环形链和数据丢失的情况。
2.在JDK1.8中,在并发执行put操作时会发生数据覆盖的情况。

图解HashMap为什么线程不安全?_愿万事胜意-CSDN博客_hashmap为什么线程不安全

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值