HashMap源码分析(四)

HashMap源码分析(四)

JDK1.8

从上几篇HashMap源码分析(一)HashMap源码分析(二)HashMap源码分析(三)我们了解了HashMap基本的数据结构,也了解了怎么生成链表的,也知道怎么动态扩容了,但这几片有几处我们当时是忽略的,比如当生成的链表个数大于8的时候。接下来我们就看一下大于8,具体是做哪些操作。

先看测试代码:

//为了测试,编写一个实体类,重写了hascode,所有的实例hashcode都是一样的
class Demo{
    String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Demo(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Demo)) return false;
        Demo demo = (Demo) o;
        return Objects.equals(getName(), demo.getName());
    }

    @Override
    public int hashCode() {

        return 123;
    }
}


 @Test
    public void test(){
        HashMap hashMap = new HashMap();
        hashMap.put(new Demo("1"),"1");
        hashMap.put(new Demo("2"),"1");
        hashMap.put(new Demo("3"),"1");
        hashMap.put(new Demo("4"),"1");
        hashMap.put(new Demo("5"),"1");
        hashMap.put(new Demo("6"),"1");
        hashMap.put(new Demo("7"),"1");
        hashMap.put(new Demo("8"),"1");
        hashMap.put(new Demo("9"),"1");
    }

前面8个put操作我们都分析过了,我们就看第九个操作,为什么是从第九个开始,看一下源码:

for (int binCount = 0; ; ++binCount) {
    if ((e = p.next) == null) {
        p.next = newNode(hash, key, value, null);
        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st //TREEIFY_THRESHOLD
            treeifyBin(tab, hash);
        break;
    }
    if (e.hash == hash &&
        ((k = e.key) == key || (key != null && key.equals(k))))
        break;
    p = e;
}

可以看到当链表的长度大于8的时候(TREEIFY_THRESHOLD,从9的时候开始),开始调用**treeifyBin()**方法。

/**
 * Replaces all linked nodes in bin at index for given hash unless
 * table is too small, in which case resizes instead.
 对于给定的哈希,在索引处替换bin中的所有链接节点,除非表太小,否则改为调整大小。
 */
final void treeifyBin(Node<K,V>[] tab, int hash) {
    int n, index; Node<K,V> e;
    if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY) //64
        resize();
    else if ((e = tab[index = (n - 1) & hash]) != null) {
        TreeNode<K,V> hd = null, tl = null;
        do {
            TreeNode<K,V> p = replacementTreeNode(e, null);
            if (tl == null)
                hd = p;
            else {
                p.prev = tl;
                tl.next = p;
            }
            tl = p;
        } while ((e = e.next) != null);
        if ((tab[index] = hd) != null)
            hd.treeify(tab);
    }
}

从注释可以看出,在数组长度小于64的时候,就是相当于扩容。

下面我们为了测试,在初始化的时候传入数组长度。

HashMap hashMap = new HashMap(64);

下面通过图来讲解:

在这里插入图片描述

上图是没有转化时候的数据结构。

在这里插入图片描述

上面就是转化程红黑树的过程,调用的treefiyBin(),然后里面有调用了treefiy().

好吧,红黑树我就暂时分析到这,说实在,分析完我也不是太懂红黑树的原理。。。记住hashMap内部是数组+链表+红黑树组成的就行了。

在网上看到下图,总结的不错,分享一下,正好可以结合我之前的博客看一下。

img

(图片来源:https://blog.csdn.net/lianhuazy167/article/details/66967698)

HashMap jdk1.7和jdk1.8的区别
JDK1.7JDK1.8
扩容的顺序先扩容,再插入先插入,再扩容
扩容的机制计算链表中每一个元素的下标判断新增的bit位是否是1,是0就是原下标,是1就是原下标+原数组长度
红黑树链表长度大于8是,转换成红黑树
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Coder_Qiang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值