HashMap内部原理详解


1、什么是HashMap?
答:HashMap 根据hash实现的一种Map接口实现类。
2、HashMap的底层数据结构?
答:在1.8之前,HashMap的数据结构:数组+链表
   在1.8之后,HashMap的数据结构:数组+链表+红黑树
3、HashMap的初始值?
答:capacity:代表table.length loadfactor:加载因子 threhold:扩容的门槛值
1)、DEFAULT_INITIAL_CAPACITY = 1<<4(初始容量)
2)、MAXIMUM_CAPACITY = 1<<30(最大容量)
3)、DEFAULT_LOAD_FACTOR = 0.75f(加载因子)
4)、TREEIFY_THRESHOLD = 8(链表转化为树门槛值)
5)、UNTREEIFY_THRESHOLD = 6(树转化为链表门槛值)
7)、loadFactor(加载因子)
8)、threshold(扩容的门槛值)
9)、size(map当前key-value的数目)
4、初始化HashMap?
答:
1)HashMap(int initialCapacity, float loadFactor) 
约束条件:0<=initialCapacity<=MAXIMUM_CAPACITY, loadFactor>=0, threshold=tableSizeFor(initialCapacity)(tableSizeFor(initialCapacity)大于等于initialCapacity的2的最小整数次幂)
2)HashMap(int initialCapacity) => HashMap(initialCapacity, DEFAULT_LOAD_FACTOR)
约束条件:同上
3) HashMap() 
约束条件:loadFactor = DEFAULT_LOAD_FACTOR
4)HashMap(Map<? extends K, ? extends V> m)
约束条件:loadFactor = DEFAULT_LOAD_FACTOR
5、put元素过程?
答:put<key, value> 允许空值
1)、通过hash函数,计算key的hash
2)、如果桶表为空,通过resize函数初始化桶表
3)、计算hash值在表中的位置:(table.length - 1) & hash, 并查看在桶表中该位置是否有值,若无,则直接在该位置创建新值 new Node<>(hash, key, value, null)
4)、若该位置有值则判断该值是否为TreeNode
5)、若不是TreeNode,则从头遍历链表,若 Node.key == key || key.equals(Node.key) 则对值进行替换,否则,在尾部进行插入,校验该桶的链表长度是否大于TREEIFY_THRESHOLD-1,若大于等于,则转化为树结构。
6)、若是ThreeNode,则插入红黑树中
7)、若size大于threshold,则通过resize进行扩容
6、get元素过程?
答:get<key> 允许空值
1)、通过hash函数,计算key的hash
2)、计算hash值在表中的位置:(table.length - 1) & hash, 并查看在桶表中该位置是否有值,若无,则返回空
3)、若该位置有值则判断该值是否为TreeNode
4)、若不是TreeNode,则从头遍历链表若 Node.key == key || key.equals(Node.key) 则返回,若查询不到,则返空
5)、若是ThreeNode,则从树中获取该值
7、remove元素过程?
答:remove<key>允许空值
1)、通过hash函数,计算key的hash
2)、假设桶表不为空,计算hash值在表中的位置:(table.length - 1) & hash, 并查看在桶表中该位置是否有值,若无返回空
3)、若该位置有值则判断该值是否为TreeNode
4)、若不是TreeNode,则从头遍历链表,若 Node.key == key || key.equals(Node.key) 则对值进行删除
5)、若是ThreeNode,则删除该值
NOTE:
1)、hash函数:(key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16)
2)、resize函数:
创建桶表:
(1)、没有初始化initialCapacity、loadFactor,则使用默认值初始化。
(2)、有初始值,则使用初始值初始化
(3)、创建桶表
扩容:
(1):capacity<<1且threhold<<1
(2):创建新桶表
(3):若节点为TreeNode,则通过TreeNode方式进行rehash
(4):若节点为Node,则重新进行rehash(注意:这里面用了一个技巧(e.hash & oldCap) == 0的还是放在原来的位置,其他的放在原来位置+oldCap,(e.hash & oldCap) == 0表示小于原来容量的,这个等式基于oldCap一定是2的整数次幂,并且事实上也是这样的。基于此举个例子,假设之前容量为16,则二级制表示为00010000,那么小于16的进行&操作,结果都为零)
死锁:java8的实现并不会发生死锁,因为死锁的出现主要是顺序不一致造成的。而java8的实现顺序是一致的。

do {
    next = e.next;
    if ((e.hash & oldCap) == 0) {
        if (loTail == null)
            loHead = e;
        else
            loTail.next = e;
        loTail = e;
    }
    else {
        if (hiTail == null)
            hiHead = e;
        else
            hiTail.next = e;
        hiTail = e;
    }
} while ((e = next) != null);
if (loTail != null) {
    loTail.next = null;
    newTab[j] = loHead;
}
if (hiTail != null) {
    hiTail.next = null;
    newTab[j + oldCap] = hiHead;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值