Java哈希表通过散列函数将键映射为数组下标实现快速存取,核心是“算位置、再存放”,依赖散列函数、底层数组(Node[] table)和链地址法冲突处理机制;null键被特殊处理,固定存于下标0位置。

哈希表在 Java 中通过散列函数将键(key)映射为数组下标,从而实现快速存取。核心不是“直接放”,而是“算位置、再存放”,整个过程依赖散列函数 + 底层数组 + 冲突处理机制。
散列函数决定存储位置
Java 哈希表(如 HashMap)默认使用 key.hashCode() % tableSize 的变体来计算索引(实际是 (n - 1) & hash,其中 n 是数组长度,要求为 2 的幂)。这个运算本质就是散列函数的作用:把任意 key 转成一个非负整数,再压缩到合法下标范围内。
例如:
- 插入 key = 17,当前桶数组长度为 16 → 计算 hash 值(假设为 17)→ 17 & (16-1) = 17 & 15 = 1 → 存入下标 1 的位置
- 插入 key = 33 → 33 & 15 = 1 → 也映射到下标 1 → 此时发生冲突
底层数组承载数据单元
Java 的 HashMap 底层是一个 Node<K,V>[] table 数组。每个数组元素(桶)不直接存值,而是存链表头节点或红黑树根节点(当链表长度 ≥ 8 且数组长度 ≥ 64 时树化)。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
也就是说:
- 散列函数输出的是“桶号”,不是最终内存地址
- 真正存储的是 Node 对象,包含 key、value、hash、next(或 treebin)字段
- 同一个桶里可能有多个 Node,靠 key.equals() 进一步区分
冲突发生后如何继续存储
当不同 key 算出相同桶下标时,必须解决冲突。Java HashMap 采用:
- 链地址法(拉链法):新节点头插或尾插进该桶的链表(JDK 8 后为尾插,避免多线程扩容死链)
- 红黑树降级策略:链表长度达阈值且表够大时转为红黑树,保证最坏查找为 O(log n)
- 不采用开放寻址(如线性探测),所以不会“往下一个空位挪”
key 为空时的特殊处理
HashMap 允许一个 null key。它被硬编码存放在数组的 下标 0 位置,不参与散列计算——因为 null.hashCode() 会抛异常。这是散列表设计中的显式约定,不是散列函数的结果。

















