详解集合之HashMap——HashMap内部结构,自动扩容机制,为什么需要重写hashcode和equals方法

本文详细探讨了HashMap的底层实现,包括它作为一个键值对Node数组的结构,自动扩容机制,以及为何需要重写hashcode和equals方法。在HashMap的创建过程中,构造方法会设置初始容量和加载因子。添加元素时,通过put方法计算key的hash值并映射到哈希表索引,处理冲突时可能涉及红黑树转换。同时,文章指出重写hashcode和equals方法对于正确操作HashMap的重要性。

HashMap底层实现是一个键值对Node数组,而Node实现了键值对Map.Entry接口

HashMap类继承结构图

 

 

1. HashMap对象的创建

1.1 默认的构造方法——只指定自动扩容时的加载因子loadFactor

 

1.2 对初始容量或加载因子设定的构造方法

通过tableSizeFor源码分析,我们知道如果传入参数是2的次方,比如1,2,4,8...,那么最终的返回值就是本身;如果不是,那么返回的是大于参数值,且最接近参数值的2的次方。如9,返回的是16,15返回的也是16。所以我们总结tableSizeFor方法的作用就是得到大于原始值的最小的2的次方

 

1.3 传入Map对象的构造方法

 

总结:HashMap的构造方法主要就是对threshold和loadFactor属性赋值;但是我们发现只有默认构造方法没有对threshold属性赋值,而且类中有个常量属性DEFAULT_INITIAL_CAPACITY,这里先记住,后面会有用。

 

2. HashMap添加元素

2.1 Map添加元素使用的是put方法,参数是key和value。内部调用putVal方法,参数是key的hash值,key,value,false,以及true,记住这些参数,后面分析putVal方法需要使用。

2.2 putVal源码分析

2.3 总结:不考虑特殊情况以及数值超界,添加元素的逻辑为:根据key的hashcode简单变形得到hash值,然后将该hash值映射到哈希表的索引。判断该索引是否为null,为null,则使用信息创建新节点;不为null则判断该索引的第一个节点是否和当前要添加节点的hash值以及==或equals相等,相等更新该节点的值即可。如果没找到则判断当前索引是否已经转为红黑树(转为树的条件是哈希表数组大小大于等于64,并且单链表节点数大于等于8),如果是红黑树,则使用红黑树的节点添加方法;如果不是,则一直比对当前节点链表,找到更新值,找不到添加至尾部。所以我们需要重写hashcode方法和equals方法,不然自带的hashcode比较的是内存地址。

 

3. HashMap通过key获取元素

 

4. HashMap其它常用方法

4.1 keySet和values方法得到key集合和value集合,keySet和values是内部属性。

 

4.2 remove方法移除某元素——先寻找再移除

4.3 clear方法清空

4.4 containsKey方法判断是否包含key

4.5 containsValue方法判断哈希表是否包含某个value,很费时间,少用。

 

5. HashSet。

5.1 HashSet构造方法内部实际使用HashMap对象。

5.2 数据存储时,只记录key,不记录value而已,value使用内部的一个Object类型常量PRESENT

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值