首先,HashMap的初始化的数组长度一定是2的n次的,每次扩容仍是原来的2倍的话,就不会破坏这个规律,每次扩容后,原数据都会进行数据迁移,根据二进制的计算,扩容后数据要么在原来位置,要么在【原来位置+扩容长度】,这样就不需要重新hash,效率上更高。 HashMap中,如果想存入数据,首先它需要根据key的哈希值去定位落入哪...
一、HashMap 的长度为什么是 2 的 N 次方 为了能让HashMap存数据和取数据的效率高,尽可能地减少hash值碰撞,也就是说尽量把数据能平均分配,每个链表或者红黑树长度尽量相等。 取余(%)操作中,如果除数是2的幂次,则等价于与其除数减一的与(&)操作。 即:hash%length == hash &(length -1),这个等式成立的前...
当HashMap需要扩容时,新的容量总是2的N次方。这背后有几个原因: 空间利用效率:假设HashMap当前的容量是2的N次方,扩容后容量变为2的N+1次方。此时,每个桶的大小变为原来的两倍。如果HashMap的大小正好是2的N次方,那么它就可以完美地填满整个数组,不会浪费任何空间。 减少哈希冲突:如果容量不是2的N次方,那么计...
2的n次方实际就是1后面n个0,2的n次方-1 实际就是n个1; 例如长度为9时候,3&(9-1)=0 2&(9-1)=0 ,都在0上,碰撞了; 例如长度为8时候,3&(8-1)=3 2&(8-1)=2 ,不同位置上,不碰撞; 其实就是按位“与”的时候,每一位都能 &1 ,也就是和1111……1111111进行与运算 0000 0011 3 & 0000 ...
1.2 为什么 HashMap 初始化即使给定长度,依然要重新计算一个 2^n^ 的数? PS: 这个方法是 HashMap 用于计算初始化容量,结果是返回大于给定值的第一个偶数,比如 : new HashMap(10),其实实际长度是 16; new HashMap(18),实际长度是32; new HashMap(40),实际长度64。
HashMap的数组长度为何必须是2的n次方 扩容方便,数字位移计算方便效率高; 计算元素下标使用的方式是key的hash & (数组length - 1),由于length是2^n,转换成二进制后2^-1最低位就全部都是1,比如111,就相当于是数组长度的掩码,那么hash & 111就可以将数组的每一位都覆盖,加入数组长度不是2^n,那么length-1...
HashMap 的长度设计为 2 的幂次方的原因主要有以下几个: 高效索引计算: 在HashMap 中,当插入一个键值对时,需要根据 key 的哈希码计算出该元素在数组中的存储位置。计算方式是使用(n - 1) & hash来获取对应的数组下标,其中n是数组的长度,hash是经过哈希函数计算后的结果。如果数组长度n是 2 的幂次方,那么...
能保证 索引值 肯定在 capacity 中,不会超出数组长度 (n - 1) & hash,当n为2次幂时,会满足一个公式:(n - 1) & hash = hash % n 2.为什么要通过 (n - 1) & hash 决定桶的索引呢? 1)key具体应该在哪个桶中,肯定要和key挂钩的,HashMap顾名思义就是通过hash算法高效的把存储的数据查询出来,所以...
当HashMap容量为16=2的4次方时,则是后4位参与&运算当HashMap容量为32=2的5次方时,则是后5位参与&运算当HashMap容量为2ⁿ时,则是后n位参与&运算,获取元素下标。 因为在大多数情况下,HashMap的容量是小于2的16次方,运算得到的下标都是与hashcode的二进制的后16位做&运算的到的值。要想得到的hash...
首先我们看下HashMap中的源码当中那里奠定了长度是2的n次方,并且是靠近cap这个值最近的2的n次方 static final int tableSizeFor(int cap) { // 首先cap-1使得n的最后一位和cap最后一位绝对不一样 int n = cap - 1; // 向右无符号的移动了1位,并使用或运算使n的所有有1的位上全部是1 ...