Java底层探究--HashMap

23 篇文章 0 订阅

Java底层探究–HashMap

简介

HashMap在是java中一种常用的数据类型,其数据存储是以键-值对的形式进行存储,并且,键是不可以重复的,可以为null,作为双列,元素无序的Map集合,在使用中有着不可替代的作用;

相关类与接口

HashMap继承自AbstractMap,而AbstarctMap实现了Map接口;Map接口中定义了get,put,containsKey,containsValue等方法;

底层实现

HashMap的实现是基于Hash表(数组加链表,其中数组查找快,链表增删快)的数据结构,(其链表结构在JDK1.8以后,当某一链表长度超过8,且数组长度超过64时,会将链表转换为红黑树,所以也可以将Hash表看成是数组加链表加红黑树的数据结构,红黑树是一种平衡的树,其左右子树高度近乎一致,也使得查找时间复杂度为log(n));
在这里插入图片描述

红黑树的特点

(1).所有节点均为红色或者黑色;
(2).红色节点的两个子结点一定是黑色结点;
(3).叶子结点一定是黑色结点;
(3).从根节点出发,达到每一个叶子结点所经过的黑色结点数相同;

在HashMap中其键不可以重复,在其键进行存储时,会使用hashCode()方法进行判断,如果不同则判断不同,如果相同,则调用其equals()方法进行判断,如果相同,则判断键重复,会覆盖掉原有键的值,如果不同,则进行存储;所以在其中存储的key的类对象要求重写hashCode()和equals()方法;

Hash冲突

使用哈希的方法,也就是HashMap在进行key的存储时,会使用其hash值对其容量-1进行取余操作,如当前容量为16,需要存储的键的哈希值为31,则计算得到将其存放在下标为1的链表上,但是很容易想到,如果又有一个哈希值为46的元素,那么根据计算,其存储位置又是1,这时,就会链接到其链表的下一个位置;
这使用的方法就是处理hash冲突时常用的拉链法;

此外,处理哈希冲突的方法还有:

开放定址法:空间表中空间不足时,会去寻找下一个空的散列地址;

双哈希法:建立多个hash函数,当第一个发生冲突会使用第二个,第三个,直到不发生冲突;

建立公共溢出区:建立基本表和溢出表,将发生哈希冲突的元素均存入到溢出表中;

HashMap的性能

影响其性能的因素有两个:初始容量和负载因子;即初始哈希表长度和哈希表的扩容时机,如果初始容量太大,使用的时候只存储很少的数据,会造成空间的大量浪费,如果容量太小,使用时就需要多次扩容,降低效率;

初始容量是创建hash表时的数组容量,默认是16,最大为2的30次方:

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
static final int MAXIMUM_CAPACITY = 1 << 30;

负载因子默认为0.75;阈值=负载因子*容量,即达到容量的3/4会进行扩容操作,其容量左移一位,即为原容量的2倍,而ArrayList的扩容为达到最大值才进行扩容,并扩容为原有的1.5倍;

static final float DEFAULT_LOAD_FACTOR = 0.75f;

扰动函数

为什么需要扰动函数呢,在数据进行hash值计算时,往往会有在某一数据值附近聚集,那么会很容易发生哈希冲突,使用扰动函数,可以降低其聚集在一起的概率;

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

h >>> 16 表示将hashCode的二进制码右移16位

^ 表示按位异或,即2个二进制码异或,2个数不同则结果为1,否则为0。
其好处就是可以混合高位和低位,加大随机性;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值