HashMap的四个成员方法详解(put、remove、resize、get)
在了解HashMap的构造方法之后,就进行实例部分的四个基本的成员方法,也是我平常经常用到的成员方法:
增加方法(put):
put方法在在实例中可以直接用.put()实现,这里解释一下put方法的源码详细实现步骤:
(1)先通过hash值计算出key映射到哪个桶
(2)如果桶上没有碰撞,冲突,则直接插入
(3)如果出现碰撞冲突,则需要处理冲突,a:如果该桶使用红黑树处理冲突,则调用红黑树的方法插入数据。b:否则采用传统的链式方法插入,如果链表的长度达到临界值,则转变为红黑树
(4)如果桶中存在重复的键,则将该值替换为新值value
(5)如果size大于阈值threshold,则进行扩容
这里再讲下hash方法:首先计算出key的hashCode,赋值给h,然后h无符号右移16位的二进制进行按位异或得到最后的hash值,这些都可以从源码中找到,如果有感兴趣的,可以私聊我。
扩容方法(resize):
每次进行扩容操作,都会伴随着一次重新hash分配,并且会遍历hash表中所有的元素,这是非常耗时的,因此应该进行避免resize。
优化的是,HashMap在进行扩容时,使用的rehash方式很巧妙,因为每次扩容都是翻倍,因此与原来计算(n-1)与hash相与的结果相比,只是多了一个bit位,所以结点要么就在原来的位置,要么就被分配到“原位置+旧容量”的位置,这个我们通过一个实例来图解了解:
这里我们要记住,计算索引的方法是hash&(n-1) 因此,在扩容HashMap时,不再重新计算Hash,只需要看原来的Hash值新增的哪个bit位是0还是1,如果是0,则索引没有变化,如果是1,索引就变成“原位置+旧容量”。
删除方法(remove):
删除方法是根据key进行删除,与put类似,.remove()。
首先找到元素的位置,如果是链表就遍历链表找到元素之后删除,如果是红黑树就遍历树然后找到之后删除,注意,树小于6时要转变为链表
查找元素方法(get):
查找方法,是通过key找到valueget方法源码的具体实现步骤:
(1)通过hash值获取该key映射到的桶
(2)桶上的key就是要查找的key,直接找到并返回
(3)桶上的key不是要找的key,则查看后续的结点
a:如果后续结点是红黑树结点,通过调用红黑树的getTreeNode方法根据key获得value
b: 如果后续结点是链表结点,则通过循环遍历链表,根据key获得value
查找红黑树,由于添加时已经保证这个树是有序的,左侧小,右侧大,因此查找时基本是折半查找,效率较高,这里跟插入一样,如果对比结点的哈希值和要找的哈希值相等,就会判断key是否相等,相等就直接返回,不相等就从子树中继续查找。若为树,则在树中用Key.equals(k)查找,O(logn)。若为链表,则在链表中用key.equals(k)查找,O(n)。