首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

图文并茂:HashMap经典详解!

} 通过源码可以看出初始化时并没有初始化数组 table,那只能在 put 操作时放入了,为什么要这样做?...“与” 操作的结果就是散列值的高位全部归零,只保留低位值,用来做数组下标访问。以初始长度 16 为例,16‑1=15。2 进制表示是 00000000 0000000000001111。...而且混合后的低位掺杂了高位的部分特征,这样高位的信息也被变相保留下来。 putVal 方法 HashMap 的 put 方法执行过程可以通过下图来理解,自己有兴趣可以去对比源码更清楚地研究学习。..., key, value, null); // 如果hash值对应的桶内有数据解决冲突,再放入桶中 else { Node e; K k...有一点注意区别,JDK1.7 中 rehash 的时候,旧链表迁移新链表的时候,如果在新表的数组索引位置相同,则链表元素会倒置,但是从上图可以看出,JDK1.8 不会倒置。

25220

图文并茂,HashMap经典详解!【文末送书】

} 通过源码可以看出初始化时并没有初始化数组table,那只能在put操作时放入了,为什么要这样做?...“与”操作的结果就是散列值的高位全部归零,只保留低位值,用来做数组下标访问。以初始长度16为例,16‑1=15。2进制表示是00000000 0000000000001111。...而且混合后的低位掺杂了高位的部分特征,这样高位的信息也被变相保留下来。..., key, value, null); // 如果hash值对应的桶内有数据解决冲突,再放入桶中 else { Node e; K k...有一点注意区别,JDK1.7中rehash的时候,旧链表迁移新链表的时候,如果在新表的数组索引位置相同,则链表元素会倒置,但是从上图可以看出,JDK1.8不会倒置。

29510
  • 您找到你想要的搜索结果了吗?
    是的
    没有找到

    Java源码解读 --- HashMap&ConcurrentHashMap

    从上面我们可以看到,这个数组并没有初始化,那么当我们put元素的时候,这个数组是如何初始化的呢?...3、如何将元素放入数组? 初始化了一个长度为16的数组,那么索引就是 0 ~ 15,当put元素的时候,如何知晓元素是放入哪个位置呢?Node内部类的hash属性就起作用了。...有三种情况: 如果是单个元素,那就用 hash & (newLength - 1 ); 如果是链表,那么就用看 hash & oldLength 的计算结果是否为0(oldLength表示旧数组的容量)...上面说了HashMap通过计算 hash & (数组长度 - 1 ) 的值来确定元素放入数组中哪个位置。当两个元素计算出来的值一样时,如何处理?...小结:往HashMap中put元素主要分为以下几个步骤: hash(key),计算key的hash,用key的hashCode值的高16位和低16位进行异或运算; 调用resize方法初始化数组,默认初始化大小为

    56820

    Java之HashMap解剖学

    } 通过源码可以看出初始化时并没有初始化数组table,那只能在put操作时放入了,为什么要这样做?...“与”操作的结果就是散列值的高位全部归零,只保留低位值,用来做数组下标访问。以初始长度16为例,16‑1=15。2进制表示是00000000 0000000000001111。...而且混合后的低位掺杂了高位的部分特征,这样高位的信息也被变相保留下来。 putVal方法 HashMap的put方法执行过程可以通过下图来理解,自己有兴趣可以去对比源码更清楚地研究学习。 ?..., key, value, null); // 如果hash值对应的桶内有数据解决冲突,再放入桶中 else { Node e; K k...有一点注意区别,JDK1.7中rehash的时候,旧链表迁移新链表的时候,如果在新表的数组索引位置相同,则链表元素会倒置,但是从上图可以看出,JDK1.8不会倒置。

    43020

    HashMap内部

    key-value后扩容的值16或者是原先的长度,n-1代表最大的索引位, //使用(n-1)&hash,得到的值必然是0~最大索引位之间的一个数,所以得到的值可以用来做放入key-value...oleCap–旧容量 newCap–新容量 oldThr–旧临界值 newThr–新临界值 final Node[] resize() { Node[] oldTab...0 : oldTab.length; //获取旧容量 int oldThr = threshold; //获取旧临界值 int newCap, newThr = 0; if...大致步骤 1.HashMap中维护了一个Node类型的数组–table;创建对象时,只对loadFactor初始化为0.75,table还是保持null 2.当第一次put时,初始table的容量为...resize()进行二倍扩容,并打乱原来的顺序重新排列 ④当一个桶中的链表节点数>8,且table的容量大于64时,将链表结构变成红黑树

    78720

    jdk8HashMap源码解读一【源码】

    HashMap 是基于 hashing 的原理 我们使用 put(key, value) 存储对象到 HashMap 中,使用 get(key) 从 HashMap 中获取对象。...当我们给 put() 方法传递键和值时,我们先对键调用 hashCode() 方法,计算并返回的 hashCode 是用于找到 Map 数组的 bucket 位置来储存 Node 对象。...=null 说明存在旧值的key与要插入的key"相等" // 对于我们分析的put操作,下面这个 if 其实就是进行 "值覆盖",然后返回旧值 if (e !...然后再计算下标 如果没有碰撞,直接放入桶中(碰撞的意思是计算得到的 Hash 值相同,需要放到同一个 bucket 中) 如果碰撞了,以链表的方式链接到后面 如果链表长度超过阀值(TREEIFY THRESHOLD...当我们调用 get() 方法,HashMap 会使用键对象的 hashcode 找到 bucket 位置,找到 bucket 位置之后,会调用 keys.equals() 方法去找到链表中正确的节点,最终找到要找的值对象

    43810

    JDK1.8HashMap源码学习-put操作以及扩容(一)

    /** * 真正执行put的操作 * hash key的hash值 是通过hash函数计算得出 * key 我们要放入的key * value 要放入的值 * onlyIfAbsent true 不覆盖存在...而且put值走的路径是 在一个桶中增加值,达到容量阀值后先进行数组扩容,直到数组长度达到64,然后接着在该桶中增加值,链表长度达到8后,触发该桶从单向列表转变为双向列表再树化,这样我们可以把主要的情况都涉及到...当我们第一次put值,即hash为6的时候,因为数组并没有初始化,先会初始化一个长度为16的数组,接着计算放入的key的数组下标是多少,即 i = (n - 1) & hash] 计算出下标后判断该数组下标中是否有节点...接着我们继续执行put操作,将一系列值均put到数组下标为6的桶中。直到该桶中的节点数达到8。...key值hash与新长度取余下标可能就有新的值,比如,6%32=6,54%32=22,那么就是遍历旧数组每个桶中的每个节点的值,然后重新计算位置,并进行操作。

    55930

    【大家的项目】JServer:用json文件做数据存储的零代码API测试服务器

    jserver Rust 编写的 json 接口和静态文件服务器 灵感来自 typicode 采用 nodejs 编写的 json-server 30秒 零代码 实现模拟全功能 REST 接口(真的)...你需要知道: 当你发送 POST, PUT, PATCH 或 DELETE 请求时,修改的数据将会自动保存到 data.json ,并发调用时保存也是安全的。...请求体应该是合法的 JSON 对象或单个值。(比如 {"name": "Foobar"} "test string" 83.01 ) 唯一标识(默认为 id )是不可修改的。...PUT 或 PATCH 请求中的任何 id 值都会被忽略。只有 POST 请求中的 id 会使用,不允许重复的 id 。...DELETE /api/posts/1 对象或单值 路由 GET /api/profile POST /api/profile PUT /api/profile PATCH /api

    18120

    HashMap、LRU、散列表

    阀值 = 当前数组长度✖负载因子 hashmap中默认负载因子为0.75,长度默认是16,默认情况下第一次扩容判断阀值是16 ✖ 0.75 = 12;所以第一次存键值对的时候,在存到第13个键值对时就需要扩容了...为了提高性能,该容器提供了一个优化:当删除key键时,不是立马删除这一项,而是留下需要删除的选项给一个删除的标记。该条目可以被重新用于相同的key,或者被单个垃圾收集器逐步删除完全部的条目后压缩。...调用put插入新的对象也是存储在链表尾端,这样当内存缓存达到设定的最大值时,将链表头部的对象(近期最少用到的)移除。 内存中使用LRUCache是最合适的。...我们通过散列函数把元素的键值映射为下标,然后将数据存储在数组中对应下标的位置。当我们按照键值查询元素时,我们用同样的散列函数,将键值转化数组下标,从对应的数组下标的位置取数据。...当有新数据要插入时,我们将新数据插入新散列表中,并且从老的散列表中拿出一个数据放入到新散列表。每次插入一个数据到散列表,我们都重复上面的过程。

    1.1K51

    揭秘Java中的瑞士军刀——HashMap源码解析

    它的工作原理可以简化为以下几个步骤: 初始化 初始化:当我们创建一个HashMap对象时,它会调用构造函数,创建一个新的数组和一个空的Node对象列表。...查找 当我们需要查找一个键对应的值时,同样会先计算出键的hashCode()值,然后根据该值找到数组中的一个位置。...删除 当我们需要从HashMap中删除一个键值对时,首先会根据键的hashCode()值找到数组中的一个位置,然后检查该位置的Node对象是否包含我们要删除的键。...根据给定的哈希值、键、值等信息,找到要移除的节点。如果节点存在且满足匹配条件(matchValue为true时),则将节点从链表中移除,并返回该节点;否则返回null。...具体解释如下: 根据给定的哈希值、键、值等信息,在哈希表中找到要移除的节点。 如果节点存在且满足匹配条件(matchValue为true时),则将节点从链表中移除,并返回该节点;否则返回null。

    18430

    恕我直言你可能真的不会java第12篇-如何使用Stream API对Map元素排序

    这个函数有三个参数: 参数一:向map里面put的键 参数二:向map里面put的值 参数三:如果键发生重复,如何处理值。可以是一个函数,也可以写成lambda表达式。...当我们调用merge函数,往map里面放入k:2键值对的时候,k键发生重复,就执行后面的lambda表达式。...表达式的含义是:返回旧值oldVal加上新值newVal(1+2),现在map里面只有一项元素那就是k:3。 其实lambda表达式很简单:表示匿名函数,箭头左侧是参数,箭头右侧是函数体。...("United States", 1); codes.put("Germany", 49); codes.put("France", 33); codes.put("China", 86); codes.put...由于本例中没有重复的key,所以新值旧值随便返回一个即可。

    86440

    庖丁解牛:NIO核心概念与机制详解 02 _ 缓冲区的细节实现

    同样,如果要将原始数据放入缓冲区中,就要使用访问方法 put()。...同样,在写入通道时,是从缓冲区中获取数据。 position 值跟踪从缓冲区中获取了多少数据。更准确地说,它指定下一个字节来自数组的哪一个元素。...Limit limit 变量表明还有多少数据需要取出(在从缓冲区写入通道时),或者还有多少空间可以放入数据(在从通道读入缓冲区时)。 position 总是小于或者等于 limit。...例如,可能需要将用户数据保存到磁盘。在这种情况下,必须将这些数据直接放入缓冲区,然后用通道将缓冲区写入磁盘。 或者,可能想要从磁盘读取用户数据。...index, byte b ); 第一个方法 写入(put) 单个字节。

    14430

    一步步实现React-Hooks核心原理

    因为在useState返回的时候,state就指向了初始值,所以后面即使counter的值改变了,打印出来的仍然就旧值。我们想要的是,返回一个变量的同时,还能让这个变量和真实状态同步。那如何来实现呢?...但还有一个问题,就是useState和useEffect每个组件中只能用一次。那么怎么才能支持使用多次hooks呢,我们可以将hooks保存到一个数组中。...这是为了避免useState闭包包住旧的currentHook的值。...因为在useState返回的时候,state就指向了初始值,所以后面即使counter的值改变了,打印出来的仍然就旧值。我们想要的是,返回一个变量的同时,还能让这个变量和真实状态同步。那如何来实现呢?...这是为了避免useState闭包包住旧的currentHook的值。

    2.3K30

    hashmap扩容后数据的迁移_HashMap扩容

    上文回顾 在上文深入源码分析HashMap到底是怎样将元素put进去的 我们着重分析了无参构造函数是如何创建map对象和HashMap是如何将第一个元素put进table的。...oldCap为1569 & 16结果为0,所以将e赋值给loHead,同时链表尾部loTail也指向e 由于只有两个元素,循环到此结束了 最后将loHead放在newTab[1]即在新数组中与旧数组位置相同的地方...见源码457,然后在put第一个元素resize时,婉转的传递给newCap 4、put元素时,元素的位置取决于数组的长度和key的hash值按位与的结果i = (n - 1) & hash源码630...4.1 如果这里没有元素,直接放这 4.2 如果有,判断是不是键冲突(源码634),直接新值覆盖旧值*(源码657) 4.3 如果有且不是键冲突,则将其放在原元素的next位置(源码642) 5、只有当...、扩容时,元素在新表中的位置分情况 7.1 当元素只是孤家寡人即元素的next==null(源码)711时,位置为e.hash & (newCap - 1)(源码712) 7.2 当元素有next节点时

    1.1K51

    HashMap底层实现原理解析-JDK8

    ----- 1 HashMap中的节点 1.Node 节点 Node是HashMap中用来承载我们的数据载体。我们通过put,get 方法用来存储或获取值最终都是体现在Node上。...默认值1 << 4 (16) 当我们new HashMap() 时,如果在构造器中不传值,或者传的值小于16 则HashMap会生成一个默认值是16的位桶数组。...当我们插入一个元素至位桶数组中(未发生hash碰撞的情况)时会检查是否需要扩容,依据是当前位桶数组长度 负载因子 是否小等于当前插入元素的下标。...= null) hd.treeify(tab); } } 6 HashMap扩容 当HashMap 在put值时,如果 HashMpa 为空,或者...0 : oldTab.length; //旧的容量 int oldThr = threshold; //旧的扩容临界值 int newCap, newThr = 0; /

    49880

    HashMap的设计原理和实现分析

    最后,请读者看一个实例:      默认创建的HashMap map =new HashMap();map的容量是 16,那么,当我们往 map中添加第几个完全不同的键值对时,...详细流程如下列的代码所示: /** * 将键值对存到HashMap中,如果Key在HashMap中已经存在,那么最终返回被替换掉的Value值。...将旧数组的Entry[] table中的链表重新计算hash值,然后重新均匀地放置到新的扩充数组中;      3. ...值放入HashMap中,会出现HashMap“工作异常”的问题,会出现你不希望的情况。...Key值放入HashMap中,我们想要的结果是:HashMap中的Entry键值对数目应该就一个,并且Entry对象的Value值应该是由"test1" 替换成"test2",但是实际的结果是

    36630
    领券