JAVA常用类源码自学之路-HASHMAP
HashMap和HashTable一样,都是Map集合的不同实现。与HashTable不同的是,HashMap允许值为null的key和value。且HashMap是非线程安全的,在多线程环境下使用须谨慎(可采用线程安全的ConcurrentHashMap)。此外,HashMap存储无序
HashMap存储时,根据key值的hashcode与内部维护的数组长度取模,决定存储的位置。假设hash函数能够均匀的存储数据,那么put和get操作花费时间是一样的。遍历Map花费的时间跟容量成比例的,所以在设置需要合理设置初始容量以及负载因子,初始容量不宜过高,或负载因子(loadFactory)不宜过低。
HashMap有两个参数可以影响到其性能,一个是容量capacity(Entry的数目),另一个是load factor(负载因子)。负载因子load factor主要用于衡量hashmap是否需要扩容,当entry的数量达到边界( capacity * loadfactor)时,HashMap则会自动扩容(内部数据结构重建,重新hash,此时HashMap内部的entry数目几近之前的两倍),以保证后续的数据可存入。
默认的负载因子为0.75,平衡了时间和空间。过高虽会降低空间占用率,但是查找的消耗时间会增加。在设置初始容量时,需要同时考虑到目标容量以及负载因子,从而减少rehash操作。初始容量大于 capacity/loadfactor时,将不会进行rehash操作。
关键方法:
1. HashMap内部数组长度计算(此方法的目的主要用于保证HashMap内部维护的table长度始终为2的幂。”|” 为按位或运算,即只要有1个是1的位,结果为1,否则为0。“>>>”2的幂运算 )。
![]()
2. HashMap扩容
扩容时,先根据当前数组的容量,以及扩容的阈值threshold来计算新数组的容量,为之前的两倍。
![]()
扩容完成之后,将原数组的元素复制到新数组中,即完成扩容。
3. putVal
HashMap最常用的put方法,根据key的hash值来决定元素存储位置。
![]()
4. get 方法
根据key的hash值找到Node节点,再循环node表,根据key值去匹配node节点表中对应的值。
HashMap的存储结构示意图: