jdk1.7 hashmap

本文深入探讨了HashMap在不同JDK版本中的实现差异,包括数组+链表和数组+链表+红黑树的底层存储机制。详细分析了HashMap的关键属性如初始容量、最大容量、加载因子等,并解释了其内部数据结构Entry的组成。通过关键代码片段阐述了HashMap的基本操作如添加、获取和删除元素的过程,特别关注扩容机制及其实现细节。

1.底层存储原理

JDK1.7 数组+链表

JDK1.8 数组+链表+红黑树

数组在内存中是需要一块连续的内存来存储,链表不需要

数组的特性: 由于数组在内存中是连续的且有索引(下标) 所以查询非常快复杂度O(1) 但是添加比较慢,最理想的状态就是O(1) 最不理想的状态是O(n) 

O(1)的情况就是刚好插入到末尾 前面的数据都不需要移动

O(n)的情况是刚好插首位,其他的数据都需要向后移动一位

链表新增快,查询慢

查询需要遍历整个链表,最理想的状态就是第一个元素就是我们要找的O(1),

最差的状态就是最后一个使我们要查的元素 O(n) 

链表的插入采用头插法 复杂度O(1)

 2.关键属性

// 默认初始容量 - 必须是 2 的幂。
static final int DEFAULT_INITIAL_CAPACITY = 16;

// 最大容量 显示指定时也必须是2的幂
static final int MAXIMUM_CAPACITY = 1 << 30;

//默认加载因子 (也就是有3/4被使用则扩容 扩容2倍)
static final float DEFAULT_LOAD_FACTOR = 0.75f;

//表格 真正用于存放数据的数组,根据需要调整大小。长度必须始终是 2 的幂。
transient Entry<K,V>[] table;

//map中已添加的数据总数
transient int size;

// 阈值 大于等于该值需要进行扩容
int threshold;

// 哈希表的负载因子 我们自己指定加载因子时 此参数会覆盖上面的默认加载因子
final float loadFactor;


Entry属性

// key
final K key;

// value
V value;

// 链表指向的下一个元素
Entry<K,V> next;

// hash值
int hash;

3.关键代码

 1.构造方法

 2.put方法

计算索引的关键代码 

 

 这里就为什么创建的数组的长度必须是2的幂的原因 因为2的幂次方减一换成二进制每一位都是1,不会存在0的情况,0与任何数&都是0,不能保证离散性.

打一个比方 如果数组长度设置成5 那么5-1=4的二进制就是100 那么不管key的hash值是多少 &计算后的索引只可能返回0 或者4  索引为1,2和3的位置一定不会有数据存入 

 addEntry逻辑

 createEntry

3.get

 关键代码在getEntry(key)

4.containsKey

 实际就是调用了getKey 

5.remove(key)

 

 描述得不是很清楚 画个图

 

6.关于扩容

 

 我们以new HashMap<>(4)为例

阈值 = 默认加载因子0.75x4= 3 

 以下情况都会先扩容

 索引为0,1,2的位置都已经有数据了

当第四个数据D再put进来时 计算的数据在数组的索引是0,1,2都会满足上面的扩容条件 size = 3 满足>=threshold 且 table[bucketIndex] != null  

 

 但是如果Dput进来的时候 计算的索引是3 那么不满足扩容条件 不扩容

下面这种情况

ABC组成的链表在索引为2的位置 且长度已经为3 当Dput进来时,如果根据D的KEY计算出来的索引不是2 就不会扩容 ,如果索引为2 就会扩容

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值