接着之前的文章,我们死磕HashMap的每一个细节和用法。我们都知道创建HashMap的时候如果不指定类型,默认是HashMap<Object,Object>类型(其实就算指定了编译后也是Object类型,此处不做赘述),可能我们大部分人停留在使用层面,并没有对底层的源码实现有过过多的分析和研究,那么我们首先抛出今天的议题,为什么不建议HashMap的key使用可变对象呢?更进一步说,为什么有些公司或团队强制使用HashMap的key使用String,Long等等不可变对象呢?
在详细介绍答案之前,再问一个问题,在代码使用层面,如果key是可变对象,对我们的get查询操作有影响吗?有什么影响?
首先,还是先看一下get方法的代码:
第一个红线处直接使用null作为到数组0号位置的链表中查询,null是不可变的可以忽略,直接看第二个红线处,根据非null得key查询,看一下实现:
我们今天分析的核心就是hash方法,其功能就是根据key计算出hash值,然后用来映射到Entry<K,V>中的位置,接着看hash方法实现:
该方法的意思是,如果hashSeed不等于0且key是String的实例,直接调用底层的Hashing.stringHash32方法返回hash值,否则基于key的hashCode做散列运算,尽可能的减少碰撞,然后返回比较分散的hash值。
简单从源码层面做了一下分析,那么key是否可变与hash计算有关系吗?没错,还真有关系,hash方法是基于key的hashCode做的散列运算,那么当然不同的key有不同的hashcode(非绝对),hash方法同样会算出不同的hash值,然后映射到数组不同的位置,这一点是没有疑问的。
那假如说key是可变对象,比如说key是一个人,value是他的工作信息,第一次put之后,插入到Entry<K,V> 数组具体位置,那如果这个key对应的人对象内部属性发生变化,体重变动,那么会导致key的hashcode发生变化,反映到get操作就是,hash散列运算和之前得到的hash值发生变化,直接导致indexFor()方法映射到的 Entry<K,V>数组位置发生变化,结果就是根据这个key永远无法再找到之前插入的数据了,如果很多key都发生变化,会导致:
所以使用HashMap或者其他Map实例的时候,根据业务场景尽可能避免使用可变对象作为key,最常用的就是 Map<String,Object>或者Map<String,T>。
本篇篇幅较短,但是同样希望给大家在开发过程中带来更好的效率和体验。
本文分享自 PersistentCoder 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!