热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

HashMap(3)进阶篇--HashMap扩容机制

1.什么是resize:resize就是重新计算容量;当我们不断的向HashMap对象里不停的添加元素时,HashMap对象内部的数组就会出现无法装载更多的元素,这是对象就需要扩大数组的长

1.什么是resize:

resize就是重新计算容量;当我们不断的向HashMap对象里不停的添加元素时,HashMap对象内部的数组就会出现无法装载更多的元素,这是对象就需要扩大数组的长度,以便能装入更多的元素;当然Java里的数组是无法自动扩容的,方法是使用一个新的数组代替已有的容量小的数组;就像我们用一个小桶装水,如果想装更多的水,就得换大水桶。

2.什么时候需要resize():

当向容器添加元素的时候,会判断当前容器的元素个数,如果大于等于阈值—即当前数组的长度乘以加载因子的值的时候,就要自动扩容。

扩容:(源码 661-662)

这里写图片描述

计算阀值:

1.第一次创建Hash表时:

这里写图片描述

2.对HashMap进行扩容时:

这里写图片描述

3.源码分析:

final Node[] resize() {
    //保存旧的 Hash 数组
    Node[] oldTab = table;
    int oldCap = (oldTab == null) ? 0 : oldTab.length;
    int oldThr = threshold;
    int newCap, newThr = 0;
    if (oldCap > 0) {
        //超过最大容量,不再进行扩充
        if (oldCap >= MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return oldTab;
        }
        //容量没有超过最大值,容量变为原来的两倍
        else if ((newCap = oldCap <<1) = DEFAULT_INITIAL_CAPACITY)
                 //阀值变为原来的两倍
            newThr = oldThr <<1; 
    }
    else if (oldThr > 0) 
        newCap = oldThr;
    else {
    //阀值和容量使用默认值
        newCap = DEFAULT_INITIAL_CAPACITY;
        newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
    }
    if (newThr == 0) {
    //计算新的阀值
        float ft = (float)newCap * loadFactor;
        //阀值没有超过最大阀值,设置新的阀值
        newThr = (newCap float)MAXIMUM_CAPACITY ?
                  (int)ft : Integer.MAX_VALUE);
    }
    threshold = newThr;
    @SuppressWarnings({"rawtypes","unchecked"})
    //创建新的 Hash 表
        Node[] newTab = (Node[])new Node[newCap];
    table = newTab;
    //遍历旧的 Hash 表
    if (oldTab != null) {
        for (int j = 0; j  e;
            if ((e = oldTab[j]) != null) {
                //释放空间
                oldTab[j] = null;
                //当前节点不是以链表的形式存在
                if (e.next == null)
                    newTab[e.hash & (newCap - 1)] = e;
                    //红黑树的形式,略过
                else if (e instanceof TreeNode)
                    ((TreeNode)e).split(this, newTab, j, oldCap);
                else { 
                //以链表形式存在的节点;
                //这一段还是看下面的图解吧,搞了好久才懂得 ^_^
                    Node loHead = null, loTail = null;
                    Node hiHead = null, hiTail = null;
                    Node next;
                    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;
                    }
                }
            }
        }
    }
    return newTab;
}

以链表形式存在的节点:

存在两个数他们的 Hash 值分别为:5,21 二进制形式分别为(0101,10101)。

若没有进行扩容时容量为 16,进行扩容之后的容量为 32

坐标点的计算(计算规则 :e.hash & (newCap - 1)):

没有进行扩容时:

这里写图片描述

可以看到两个Hash值所计算的坐标是相同的。

进行扩容之后:

这里写图片描述

可以看出经过扩容之后,两次计算的坐标出现了不同,但是第二个坐标点增加了 oldCap 个长度。

再看看 e.hash & oldCap 所计算出的结果:

这里写图片描述

可以看到当 e.hash & oldCap == 0 是,原来的坐标没有发生变化,e.hash & oldCap != 0 在原来坐标的前提下增加 oldCap 。

两条链表的连接过程:

这里写图片描述

这里写图片描述

这里写图片描述

在向表中连接的时候最后一个节点的下一个节点做空。

总结:

  1. 在对 HashMap 进行扩容时,阀值会变为原来的两倍;
  2. 在对HashMap进行扩容的时候,HashMap的容量会变为原来的两倍;
  3. 扩容是一个特别耗性能的操作,所以当程序员在使用HashMap的时候,估算map的大小,初始化的时候给一个大致的数值,避免map进行频繁的扩容。
  4. 负载因子是可以修改的,也可以大于1,但是建议不要轻易修改,除非情况非常特殊。

推荐阅读
  • HashMap的扩容知识详解
    本文详细介绍了HashMap的扩容知识,包括扩容的概述、扩容条件以及1.7版本中的扩容方法。通过学习本文,读者可以全面了解HashMap的扩容机制,提升对HashMap的理解和应用能力。 ... [详细]
  • 一、HashSet1.虑重功能特性(HashMap实现)2.put(key)如果重复返回false***Add ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • PHP反射API的功能和用途详解
    本文详细介绍了PHP反射API的功能和用途,包括动态获取信息和调用对象方法的功能,以及自动加载插件、生成文档、扩充PHP语言等用途。通过反射API,可以获取类的元数据,创建类的实例,调用方法,传递参数,动态调用类的静态方法等。PHP反射API是一种内建的OOP技术扩展,通过使用Reflection、ReflectionClass和ReflectionMethod等类,可以帮助我们分析其他类、接口、方法、属性和扩展。 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了源码分析--ConcurrentHashMap与HashTable(JDK1.8)相关的知识,希望对你有一定的参考价值。  Concu ... [详细]
  • 查找给定字符串的所有不同回文子字符串原文:https://www ... [详细]
  • 图解HashMap
    什么是HashMap,文章内HashMap源码主要来自Android7.0HashMap是开发中常用的一个类,那么他究竟是什么呢?HashMap是一个存储key-value的集合, ... [详细]
  • HashMap:键值对(key-value):通过对象来对对象进行索引,用来索引的对象叫做key,其对应的对象叫做value.默认是1:1关系:存在则覆盖,当key已经存在,则利用新的va ... [详细]
  • HashTable与ConcurrentHashMap均可实现HashMap的功能,对外提供了键值对存储的数据结构。但是在内部结构及实现上有何区别,性能上的差异到底在哪里又是如何导致的 ... [详细]
  • 转载自:http:www.blogjava.netCarpenterLeearchive20160427430268.html总体介绍之所以把HashSet和HashMa ... [详细]
  • 缓存这个东西就是为了提高运行速度的,由于缓存是在寸土寸金的内存里面,不是在硬盘里面,所以容量是很有限的。LRU这个算法就是把最近一次使用时间离现在时间最远的数据删除掉。先说说List:每 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
  • 展开全部可以用反射根据给定的类名来动态生成实例62616964757a686964616fe59b9ee7ad9431333337613839比如你定义了一个类packagesam ... [详细]
author-avatar
泉州多棱汽车销售服务有限公司
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有