浅析Java中的HashMap的实现工作原理

本文详细分析了Java HashMap的工作原理,包括其内部的数组+链表+红黑树的数据结构。对比了JDK1.7和JDK1.8在扩容、键为null的处理、节点插入方式等方面的差异。总结了HashMap的特性,如初始容量、负载因子、扩容策略和树化条件。此外,还探讨了HashMap解决哈希冲突的方法和保持链表顺序的方式。
摘要由CSDN通过智能技术生成

工作原理分析

Java中的HashMap是以键值对(key-value)的形式存储元素的。HashMap需要一个hash函数,它使用hashCode()和equals()方法来向集合/从集合添加和检索元素。当调用put()方法的时候,HashMap会计算key的hash值,然后把键值对存储在集合中合适的索引上。如果key已经存在了,value会被更新成新值

HashMap的一些重要的特性是它的容量(capacity),负载因子(load factor)和扩容极限(threshold resizing)

对比jdk1.7和jdk1.8版本的不同

底层数据结构不一样,1.7是数组+链表,1.8则是数组+链表+红黑树结构(当链表长度大于8,转为红黑树)。

JDK1.8中resize()方法在表为空时,创建表;在表不为空时,扩容;而JDK1.7中resize()方法负责扩容,inflateTable()负责创建表。

1.8中没有区分键为null的情况,而1.7版本中对于键为null的情况调用putForNullKey()方法。但是两个版本中如果键为null,那么调用hash()方法得到的都将是0,所以键为null的元素都始终位于哈希表table【0】中。

当1.8中的桶中元素处于链表的情况,遍历的同时最后如果没有匹配的,直接将节点添加到链表尾部;而1.7在遍历的同时没有添加数据,而是另外调用了addEntry()方法,将节点添加到链表头部。

1.7中新增节点采用头插法,1.8中新增节点采用尾插法。这也是为什么1.8不容易出现环型链表的原因。

1.7中是通过更改hashSeed值修改节点的hash值从而达到rehash时的链表分散,而1.8中键的hash值不会改变,rehash时根据(hash&oldCap)==0将链表分散。

1.8rehash时保证原链表的顺序,而1.7中rehash时有可能改变链表的顺序(头插法导致)。

在扩容的时候:1.7在插入数据之前扩容,而1.8插入数据成功之后扩容。

简单理解

hashmap的底层是哈希表,是基于hash算法实现的,hashmap通过put(key,value)存储,通过get(key)获取,当传入key时,hashmap会调用key.hashcode()方法计算出hash值,根据 hash 值将 value 保存在 bucket 里。当计算出的 hash 值相同时,我们称之为 hash 冲突,HashMap 的做法是用链表和红黑树存储相同 hash 值的value。当 hash 冲突的个数少于等于8个时,使用链表否则使用红黑树。

总结

1、HashMap底层包括数组+链表+红黑树
2、当创建对象时将加载因子(Loadfactor)初始化为0.75.
3、当添加key-value时,通过key的hash值得到在table的索引。然后判断索引处是否有元素,如果没有元素则直接添加。如果该索引处有元素,继续判断该元素的key和准备加入的key是否相等,如果相等,则直接替换val;如果不相等需要判断是树结构还是链表结构,作出相应的处理。如果添加时发现容量不够,则需要扩容。
4、第一次添加,需要扩容table容量为16,临界值(threshold)为12(16*0.75)
5、以后在扩容,则需要扩容table容量为原来的2倍(32),临界值为原来的两倍,即24,依次类推。
6、在Java8中,如果一条链表的元素个数超过TREEIFY_THRESHOLD(默认是8),并且table的大小>=MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值