Java中的HashMap详解!详细分析HashMap的工作方式和使用原理

HashMap的工作方式

通过传递key-value对调用put() 方法时 ,HashMap使用key hashCode() 和哈希算法找到存储key-value对的索引 .Entry存储在LinkedList中,如果存在Entry, 会使用equals() 方法来检查传递的key是否存在.如果存在,就会覆盖value. 如果不存在,就会创建一个新的Entry来保存

通过传递key调用get() 方法时,再次使用key hashCode() 方法来找到数组中的索引,然后使用equals() 方法找出正确的Entry并返回Entry的值

HashMap的实现原理

Java中的数据结构映射定义了接口java.util.Map, 接口有以下四个常用的实现类:

HashMap:

Hashtable:

LinkedHashMap:

TreeMap:


Java中的HashMap详解!详细分析HashMap的工作方式和使用原理

不可变对象就是这个对象创建后,对象的hashCode值不会改变

如果对象的hashCode值发生改变,就很可能无法定位到映射的位置

HashMap的数据结构

每一个桶中存放着一个单链表的头节点

每一个节点中存储着一个键值对Entry

拉链法: 也就是链地址法,是数组和链表的结合.在每个数组元素上都有一个链表结构,当数据进行Hash之后,得到数组的下标,然后将数据存放到对应下标元素的链表上

Java中的HashMap详解!详细分析HashMap的工作方式和使用原理

HashMap构造函数

public HashMap();

public HashMap(int initialCapacity);

public HashMap(int initialCapacity, float loadFactor);

HashMap重要方法

hash(K)

	static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

比如容量大小n16,n-115(0x1111), 散列值真正生效的只是低4位,此时新增的键的hashcode() 的值如果是2,18,34这样以16的倍数为差的等差数列时,就会产生大量的哈希碰撞

使用这样的方法,将高16位和低16位进行异或,因为大部分hashcode() 的值分布已经很均匀了,即使发生碰撞也用O(logn)O(logn)O(logn)时间复杂度的红黑树进行了优化.这样通过使用异或的方法,不仅减少了系统开销,也不会因为tab长度较小时高位没有参与下标的运算引发哈希碰撞

put(K, V)

if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) 

根据hash值,定位到数组某个位置后,向位置中后面的链表添加元素时,判断元素是否一样中,首先判断hash值是否相等,然后再判断equals()

如果只对equals() 进行重写,不对hashcode() 进行重写时,依然会按照不同的两个对象处理,所以重写equals() 方法时必须也要重写hashcode() 方法


HashMap中链表结构进行遍历判断时,重写的equals() 方法判断对象是否相等的业务逻辑比较复杂,这样下来的循环遍历判断影响性能

HashMap中将hash值的判断放在前面,只要hash值不同,整个条件就是false, 不需要进行equals() 方法判断对象是否相等,提升了HashMap的性能

HashMap中是根据hashcode() 的值定位到数组的位置的,同一个数组位置中后面的链表中元素的hashcode() 的值都相同.比较hashcode() 的值没有意义,因为必定相等 .HashMap中没有直接使用hashcode() 的值,用的是对hashcode() 的值进行移位和异或运算后的hash值,这里比较的是元素的hash

resize()

treeifyBin()

get(K)

Hash冲突

因为Hash是一种压缩映射,这样每一个Entry节点无法对应到一个只属于自身的桶bucket

必然会存在多个Entry共用一个桶bucket, 拉成一个链条的情况.这种情况就是Hash冲突

Hash冲突的极端情况下,某一个桶bucket后面挂着的链表会特别长,导致遍历的效率很低

HashMap中存储的Entry较多时,需要对HashMap扩容来增加桶bucket的数量 这样对后续要存储的Entry来讲,就会大大缓解Hash冲突

HashMap总结

HashMap中MAXIMUM_CAPACITY设置为1<<30

int类型,表示HashMap的最大容量

使用 << 移位运算的结果不能超过int类型表示的最大值

使用1左移 << 运算时最大只能左移30位,否则就会溢出

HashMap中容量设置为2的整数幂次方

	final Node getNode(int hash, Object key) {
        Node[] tab; Node first, e; int n; K k;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            if ((e = first.next) != null) {
                if (first instanceof TreeNode)
                    return ((TreeNode)first).getTreeNode(hash, key);
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }

数组tab

数组长度n

需要查找的key对应的值hash

数组长度在初始情况下使用n-1转换为2进制时,存在0位,导致很多位置无法放置元素,造成空间浪费

数组的有效使用位置大量减少,增加了碰撞几率,减慢了查询速度

HashMap中的负载因子设置为0.75

P(X=k)=k!λke λ,k=0,1,…(λ是均值,k为发生次数)

Java中的HashMap详解!详细分析HashMap的工作方式和使用原理

HashMap中的元素尽量使用迭代器Iterator遍历

HashMap是非线程安全的

使用迭代器Iterator过程中,如果其余的线程同时也在修改HashMap, 就会立即抛出ConcurrentModificationException异常

fail-fast策略通过modCount实现

modCount记录修改次数

在迭代器初始化过程中将modCount的值赋值迭代器的expectedModCount

在迭代器迭代过程中,判断modCountexpectModCount是否相等.如果不相等就说明有其余线程对HashMap进行了修改

Map hashMap = new HashMap();
Iterator> entries = hashMap.entrySet().iterator();
while (entries.hasNext()) {
	Map.Entry entry = entries.next();
	System.out.println("KEY = " + entry.getKey() + ", VALUE = " + entry.getValue());
}

HashMap的使用特点



作者:攻城狮Chova
链接:https://juejin.cn/post/7084947689011413028

展开阅读全文

页面更新:2024-04-20

标签:遍历   数组   节点   线程   详解   长度   元素   原理   位置   结构   方式   方法   数据   详细   工作

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top