HashMap
2021/4/29 10:28:33
本文主要是介绍HashMap,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
HashMap
HashMap简介
HashMap是一个用于存储Key-Value键值对的集合,每一个键值对也叫做Entry。这些个键值对(Entry)分散存储在一个数组当中,这个数组就是HashMap的主干。HashMap数组每一个元素的初始值都是Null。
HashMap中的Get和Set方法
-
put方法
map.put("apple", 0);//插入一个key为“apple”的元素,接着利用一个哈希函数确定Entry的插入位置 index = hash(key) //计算出插入位置 源码中: /** * Associates the specified value with the specified key in this map. * If the map previously contained a mapping for the key, the old * value is replaced. * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return the previous value associated with <tt>key</tt>, or * <tt>null</tt> if there was no mapping for <tt>key</tt>. * (A <tt>null</tt> return can also indicate that the map * previously associated <tt>null</tt> with <tt>key</tt>.) */ public V put(K key, V value) { return putVal(hash(key), key, value, false, true); }
-
HashMap长度是有限的,当插入Entry越来越多是,会出现index冲突,这时可以用链表解决。
HashMap数组的每一个元素不止是一个Entry对象,也是一个链表的头节点。每一个Entry对象通过Next指针指向它的下一个Entry节点。当新来的Entry映射到冲突的数组位置时,只需要插入到对应的链表即可:
- get方法
map.get("apple");//首先会把输入的key做一次Hash映射,得到相应的index index = hash(key) //计算出index /** * Returns the value to which the specified key is mapped, * or {@code null} if this map contains no mapping for the key. * * <p>More formally, if this map contains a mapping from a key * {@code k} to a value {@code v} such that {@code (key==null ? k==null : * key.equals(k))}, then this method returns {@code v}; otherwise * it returns {@code null}. (There can be at most one such mapping.) * * <p>A return value of {@code null} does not <i>necessarily</i> * indicate that the map contains no mapping for the key; it's also * possible that the map explicitly maps the key to {@code null}. * The {@link #containsKey containsKey} operation may be used to * distinguish these two cases. * * @see #put(Object, Object) */ public V get(Object key) { Node<K,V> e; return (e = getNode(hash(key), key)) == null ? null : e.value; }
- 对于Hash冲突,同一个位置有可能匹配到多个Entry,这时候就需要顺着对应链表的头节点,一个一个向下来查找。
- 插入的节点一般放到头结点,HashMap的发明者认为最后插入的Entry被查找的可能性更大。
HashMap默认长度
- HashMap默认长度16,每次自动扩展或是手动初始化时,长度必须是2的幂。初始化长度为16,是为了服务从key映射到index的Hash算法。
/** * The default initial capacity - MUST be a power of two. */ static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
- 为了实现高效的Hash算法,HashMap的发明者使用了为运算的方式。
1.计算book的hashcode,结果为十进制的3029737,二进制的101110001110101110 1001。
2.假定HashMap长度是默认的16,计算Length-1的结果为十进制的15,二进制的1111。
3.把以上两个结果做与运算,101110001110101110 1001 & 1111 = 1001,十进制是9,所以 index=9。
综上所述:
Hash算法最终得到得index结果,完全取决于HashCode值得最后几位。
#进行位运算,Length是HashMap的长度 index = HashCode(key) & (Length - 1)
注意:
长度16或者其他2的幂,Length-1的值是所有二进制位全为1,这种情况下,index的结果等同于HashCode后几位的值。只要输入的HashCode本身分布均匀,Hash算法的结果就是均匀的。
高并发下的HashMap
-
Rehash
Rehash是HashMap在扩容时候的一个步骤。HashMap的容量是有限的。当经过多次元素插入,使得HashMap达到一定饱和度时,Key映射位置发生冲突的几率会逐渐提高。这时候,HashMap需要扩展它的长度,也就是进行Resize。
# HashMap的当前长度,其长度是2的幂。 /** * The default initial capacity - MUST be a power of two. */ static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 # HashMap负载因子,默认值是0.75f /** * The load factor used when none specified in constructor. */ static final float DEFAULT_LOAD_FACTOR = 0.75f;
衡量HashMap是否进行Resize的条件如下:
HashMap.Size >= Capacity * LoadFactor
-
HashMap的resize方法经过以下两个步骤:
- 扩容:创建一个新的Entry空数组,长度是原数组的2倍。
- Rehash:遍历原Entry数组,把所有的Entry重新Hash到新数组。
这篇关于HashMap的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-28一步到位:购买适合 SEO 的域名全攻略
- 2024-12-27OpenFeign服务间调用学习入门
- 2024-12-27OpenFeign服务间调用学习入门
- 2024-12-27OpenFeign学习入门:轻松掌握微服务通信
- 2024-12-27OpenFeign学习入门:轻松掌握微服务间的HTTP请求
- 2024-12-27JDK17新特性学习入门:简洁教程带你轻松上手
- 2024-12-27JMeter传递token学习入门教程
- 2024-12-27JMeter压测学习入门指南
- 2024-12-27JWT单点登录学习入门指南
- 2024-12-27JWT单点登录原理学习入门