由浅入深读懂HashMap底层原理(jdk版本1.8)

1,HashMap的底层在jdk1.7的时候是数组,也就是我们说的hash桶和链表,而在1.8的时候,是数组, 链表|红黑树。就是说要么是链表,要么是红黑树。

2, HashMap类实现了Map接口,而在Map接口中,定义了内部接口类,Entry

    interface Entry<K,V> 

而这个entry 类关注的其实就是K和V,也就是key和value。

3, HashMap的实现,实在类中加了静态内部类Node,Node则是在实现了Entry接口的前提下,增加了hash值,next值:

static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;

这里的hash,是通过hash算法对key值进行计算得出的值;
这里的key的value,则是当前操作的key和vlaue。
这里的next,是指向链表下一个元素的的内存地址。

3, 解释下next值:
因为链表这个数据结构,分为单向链表和双向链表,无论那个,它在内存中存储不是线性的,就是不是连续的,所以单向的链表,但前向需要指向下一项的地址,那么这个值就是用next这个属性来存储;而双向链表,它不仅要指明下一项的内存地址,还要知道它上一项的内存地址,这个内存地址也是存储到next中,hashmap中用的单项链表,所以用next值存储下一个node的值(下一个node同样是一个K-V键值对)。

4, hashmap中的一些基础信息:

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
static final int MAXIMUM_CAPACITY = 1 << 30;
static final float DEFAULT_LOAD_FACTOR = 0.75f;
static final int TREEIFY_THRESHOLD = 8;
static final int UNTREEIFY_THRESHOLD = 6;
static final int MIN_TREEIFY_CAPACITY = 64;

这里逐一解释:

  • hashmap如果初始化不定义大小,他的默认大小是16,源码中用移位运算 1 << 4
  • hashmap最大的容量的2的30次幂,也就是 1<< 30
  • 这里的1是二进制,就是 0001
  • 为啥用一位运算,而不是直接给值,是因为以为运算更加接近底层,他的运行效率很高。
  • 为初始化是16,这个因为内存地址是用16进制表示,而作为更加机器二进制语言的汇编语言是用16禁止表示的,所以用16。
  • 扩容因子是0.75,就是说该扩容的时候并不是当前容量满了,而是在当前容量 乘以 0.75 的时候开始扩容
  • 剩下的 8 , 6 , 64 分别是一些临界值,这些数字发生在hash碰撞的时候,多出来的k-v值的存储
  • 具体在第6项中解释。

    5, hash怎么存储:
    通过每个key值,用hash算法,都会计算出一个对应的值,这个hash值会重复吗?就看这个hash算法强不强了。当key的hash值计算出后,那么就知道把这个node点放到哪里存储了,公式是hash & (hash.size() - 1),意思就是说用key的hash值和当前hash的容量减一之后做【与】运算,就是把hash和size - 1 变为2进制,这样得到的值就是这个node节点存放的位置;那么经过【与】之后,值会重复吗? 当然会,即使hash算法再强,那么经过 【与运算】的值也会重复,一样的 结果怎么存储,这就是hash碰撞。而无论是链表还是红黑树都是解决解决hash碰撞的。、

    6, 链表和红黑树的关系
    当该位置没有数据,那么数据就进来了,且next 值为null,当发生碰撞,新的node节点要往后存储,这里有限选择链表,上一个next值就是该node节点的内存地址,如果同一位置碰撞太多,那么链表的size() 就越大,我们知道由于不是线性存储和他的数据结构,它插入删除修改是极快的,但是设计到查找就会很慢。所以,当前位置挂了 6 或者 少于 6 个,用链表; 当第 8 个时候,用要变换为红黑树;超过64个,用别的结构存储。

7, hash扩容
如果数据太多,到了扩容因子的限制,就要扩容,扩容之后的默认大小:

newThr = oldThr << 1; // double threshold

就是左移 一位,也就是乘 2.

8, 扩容之后的数据分布
第一种: 把key再次hash一次,再次 和容量 做与运算,得出不同的值存储。(rehash在1.7中)
第二种,左移之后,查看当前值的最高位,如果是1的话,那么重新分配, 是0 的话,位置不变。

10, 知识普及:
因为是2进制表示16,所以4个位数为一组,比如:0000 0000, 那前4个一组,后4个一组;
如果现在存储位置 0000 0100, 它的最高为是0, 扩容之后,为0000 1000,它的高位是1
如果是0000 10000 ,高位为1,扩容之后 0001 0000,高位是1

    不知大家明白不
    欢迎大家指正!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值