HashMap在JDK1.7和JDK1.8的区别

JDK1.7与JDK1.8中HashMap的区别

JDK 1.8 对 HashMap 进行了多项重要改进,以下是主要区别:

1. 数据结构差异

  • JDK 1.7:数组 + 链表

  • JDK 1.8:数组 + 链表 + 红黑树(当链表长度超过8时转换为红黑树)

2. 插入方式

  • JDK 1.7:头插法(新元素插入链表头部)

  • JDK 1.8:尾插法(新元素插入链表尾部)

3. 扩容机制

  • JDK 1.7

    • 先扩容再插入新元素

    • 重新计算所有元素的位置(hash & (newCap-1))

  • JDK 1.8

    • 先插入新元素再判断是否需要扩容

    • 优化了重新计算位置的算法,元素新位置要么是原位置,要么是原位置+旧容量

4. 哈希算法简化

  • JDK 1.7:使用了更复杂的哈希算法(9次扰动处理)

  • JDK 1.8:简化了哈希算法(只有1次扰动处理)

5. 并发安全性

  • 两者都不安全,但JDK 1.8改进了扩容方式,减少了死循环的可能性

6. 性能改进

  • JDK 1.8在哈希冲突严重时(链表长度>8)使用红黑树替代链表,查询时间复杂度从O(n)降到O(log n)

7. 方法实现

  • JDK 1.8新增了一些方法如:getOrDefault()putIfAbsent()compute()merge()

这些改进使得JDK 1.8中的HashMap在性能上(特别是高冲突情况下)比JDK 1.7有显著提升,同时减少了在多线程环境下出现问题的可能性。

### HashMapJDK1.7 JDK1.8 之间的实现差异 #### 数据结构 在 JDK1.7 中,`HashMap` 的底层数据结构是由数组加链表组成的。当发生哈希冲突时,所有的键值对会被存放在同一个桶中形成一条单向链表[^1]。 而在 JDK1.8 中,除了保留原有的数组加链表的数据结构外,还引入了红黑树的概念。如果某个桶中的链表长度超过了一个阈值(默认为 8),并且当前 `HashMap` 的大小超过了一定界限,则该链表会转换成红黑树,从而减少查找时间复杂度从 O(n) 到平均情况下的 O(log n)[^2]。 #### 初始化过程 对于初始化部分,在 JDK1.7 中,`table` 数组是在声明时被初始化为空数组,并且首次插入元素之前调用 `inflateTable()` 方法完成实际分配工作[^3]。然而到了 JDK1.8 版本里,“懒加载”的概念得到了应用——即只有当真正需要存储第一个键值对时才会触发真正的初始化操作;另外值得注意的是,默认情况下初始容量调整为了最接近指定容量的一个 2 的幂次方数值[^4]。 #### 扩容机制 关于扩容方面也有明显改变: - **JDK1.7**: 使用头插法来进行迁移旧有节点到新位置的过程当中可能出现循环链表的情况,进而导致死循环问题的发生概率增加。而且它的判断依据较为严格,需满足两个前提条件才能执行扩容动作:一是达到负载因子限制;二是目标索引处已有其他映射项存在。 - **JDK1.8**: 改进了这一点采用了尾插法避免上述风险的同时简化逻辑只依赖单一条件即可触发改动 —— 即每当新增后的总数量超出临界点便会立即启动扩展流程。此外它利用位运算技巧快速定位每一个条目应该迁移到的新地址[(e.hash & oldCap)==0][^3]。 #### Hash 计算方式 两代产品间另一个重要差别体现在如何计算散列码之上: - **JDK1.7** 定义了一种相对复杂的扰动函数用来进一步打乱原始hashCode分布特性以期获得更加均匀的结果集[^4]: ```java static final int hash(int h){ h ^= (h >>> 20) ^ (h >>>12); return h^(h >>> 7) ^ (h >>> 4); } ``` - **JDK1.8** 对此进行了优化精简版本如下所示不仅减少了不必要的移位次数同时也兼顾效率与效果平衡考虑特别针对null关键字做了特殊处理直接返回零值作为对应hashcode: ```java static final int hash(Object key){ int h; return (key == null) ? 0 : (h = key.hashCode())^(h >>> 16); } ``` #### Null 键的支持 无论是哪个版本都允许最多只有一个Null Key 存在于整个Map实例之中不过具体表现形式略有出入: - 在早期设计(JDK1.7)里面如果遇到这样的特殊情况则专门开辟首个槽位留给它们单独使用而不参与常规路径匹配流程. - 后续更新至最新标准后(NKD1.8),尽管依旧保持相同行为模式但内部实现细节有所调整现在即使NULL也可以像普通对象那样经历完整的HASHING步骤只不过最终得出固定常量ZERO而已因此理论上讲二者并无本质区别仅限表达手法上的转变罢了[^3]. ```python # 示例代码展示两种不同版本下 NULL KEY 插入情形对比模拟演示片段 map_17.put(None,"value") # JDK1.7 方式可能直接放置 index=0 处理 map_18.put(None,"another value") # JDK1.8 经过 HASH 函数作用同样指向 index=0 结果一致 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值