Java集合

网友投稿 340 2022-09-03


Java集合

目录概述重要的参数put函数的实现get函数的实现hash函数的实现RESIZE的实现

概述

①以数组+链表+红黑树实现。主要用来处理具有键值对特征的数据。②当链表长度大于阈值(或者红黑树的边界值,默认为 8 )并且当前数组的长度大于 64 时,此时此索引位置上的所有数据改为使用红黑树存储。③补充:将链表转换成红黑树前会判断,即便阈值大于 8,但是数组长度小于 64,此时并不会将链表变为红黑树,而是选择逬行数组扩容。④每个Node节点存储着用来定位数据索引位置的hash值,K键,V值以及指向链表下一个节点的Node next节点组成。⑤Node是HashMap的内部类,实现了Map.Entry接口,本质是一个键值对。⑥这样做的目的是因为数组比较小,尽量避开红黑树结构,这种情况下变为红黑树结构,反而会降低效率,因为红黑树需要逬行左旋,右旋,变色这些操作来保持平衡。同时数组长度小于64时,搜索时间相对要快些。所以结上所述为了提高性能和减少搜索时间,底层阈值大于8并且数组长度大于64时,链表才转换为红黑树。

重要的参数

①容量(Capacity)和负载因子(Load factor)②初始容量:容量是哈希表中桶的个数,初始容量是创建哈希表时的容量。③负载因子:负载因子是衡量哈希表在自动增加容量之前允许其达到多满的指标。 默认0.75④threshold:threshold表示所能容纳的键值对的临界值。计算公式为 数组长度 * 负载因子。⑤size:size是hashmap中实际存在的键值对数量。⑥modCount:用来记录hashmap内部结构发生变化的次数。

put函数的实现

大致思路:

对key的hashCode()做hash,然后再计算index;如果没碰撞直接放到bucket里;如果碰撞了,以链表的形式存在buckets后;如果碰撞导致链表过长(大于等于 TREEIFY_THRESHOLD )就把链表转换成红黑树;如果节点已经存在就替换old value(保证key的唯一性)如果bucket满了(超过 load factor*current capacity ),就要resize(调整大小)。

get函数的实现

大致思路:

bucket里的第一个节点,直接命中;如果有冲突,则通过key.equals(k)去查找对应的entry若为树,则在树中通过key.equals(k)查找,O(logn);若为链表,则在链表中通过key.equals(k)查找,O(n)。

hash函数的实现

//高16bit不变,低16bit和高16bit做了一个异或

static final int hash(Object key) {

int h;

return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);

}

获取HashMap的元素时,基本分两步:

1.首先根据hashCode()做hash,然后确定bucket的index;2.如果bucket的节点的key不是我们需要的,则通过keys.equals()在链表(红黑树)中找。

RESIZE的实现

当put时,如果发现目前的bucket占用程度已经超过了Load FtdykQOQNwYactor所希望的比例,那么就会发生resize。

在resize的过程,简单的说就是把bucket扩充为2倍,之后重新计算index,把节点再放到新的bucket中。元素的位置要么是在原位置,要么是在原位置再移动2次幂的位置。省去了重新计算hash值的时间,把之前的冲突的节点分散到新的bucket了

什么时候会使用HashMap?他有什么特点?

是基于Map接口的实现,存储键值对时,它可以接收null的键值,是非同步的,HashMap存储着Entry(hash, key, value, next)对象。** 你知道HashMap的工作原理吗?**通过hash的方法,通过put和get存储和获取对象。存储对象时,我们将K/V传给put方法时,它调用hashCode计算hash从而得到bucket位置,进一步存储,HashMapjava集合——HashMap会根据当前bucket的占用情况自动调整容量(超过 Load Facotr 则resize为原来的2倍)。获取对象时,我们将K传给get,它调用hashCode计算hash从而得到bucket位置,并进一步调用equals()方法确定键值对。如果发生碰撞的时候,Hashmap通过链表将产生碰撞冲突的元素组织起来,在Java 8中,如果一个bucket中碰撞冲突的元素超过某个限制(默认是8),则使用红黑树来替换链表,从而提高速度。

你知道get和put的原理吗?equals()和hashCode()的都有什么作用?

通过对key的hashCode()进行hashing,并计算下标( (n-1) & hash ),从而获得buckets的位置。如果产生碰撞,则利用key.equals()方法去链表或树http://中去查找对应的节点。

hash的实现,为什么要这样实现?

在Java 1.8的实现中,是通过hashCode()的高16位异或低16位实现的: (h =k.hashCode()) ^ (h >>> 16) ,主要是从速度、功效、质量来考虑的,这么做可以在bucket的n比较小的时候,也能保证考虑到高低bit都参tdykQOQNwY与到hash的计算中http://,同时不会有太大的开销。

如果HashMap的大小超过了负载因子( load factor )定义的容量,怎么办?

如果超过了负载因子(默认0.75),则会重新resize一个原来长度两倍的HashMap,并且重新调用hash方法。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:柱状图中最大的矩形 两种解法 (Python)
下一篇:python求圆和线段/直线的交点,纠正网上有问题的代码
相关文章

 发表评论

暂时没有评论,来抢沙发吧~