Hash 表也称散列表,也有直接译作哈希表,是一种特殊的数据结构,同数组、链表以及二叉排序树等相比较有很明显的区别:它能够快速定位到想要查找的记录,而不是与表中存在的记录的关键字进行比较来进行查找。这源于 Hash 表设计的特殊性,它采用函数映射的思想将记录的存储位置与记录的关键字关联起来,从而能够很快速地进行查找。
java.util.Hashtable 是 Java 中最早的哈希表实现,自 JDK 1.0(1996 年)就已存在。在现代 Java 中它依然保留,但仅用于向后兼容旧代码:非线程安全场景推荐使用 HashMap,需要线程安全时推荐使用 ConcurrentHashMap,两者性能和易用性都更好,Hashtable 已不建议在新代码中使用。
Hash 表的设计思想
对于一般的线性表,比如链表,如果要存储联系人信息:
张三 13980593357
李四 15828662334
王五 13409821234
张帅 13890583472
可能会设计一个结构体包含姓名、手机号码这些信息,然后把 4 个联系人的信息存到一张链表中。当要查找“李四 15828662334”这条记录是否在这张链表中,或者想要得到李四的手机号码时,可能会从链表的头结点开始遍历,依次将每个结点中的姓名同“李四”进行比较,直到查找成功或者失败为止,这种做法的时间复杂度为 O(n)。即使采用二叉排序树进行存储,也最多为 O(logn)。假设能够通过“李四”这个信息直接获取到该记录在表中的存储位置,就能省掉中间关键字比较的这个环节,复杂度直接降到 O(1)。Hash 表就能够达到这样的效果。
Hash 表采用一个映射函数 f : key -> address 将关键字映射到该记录在表中的存储位置,从而在想要查找该记录时,可以直接根据关键字和映射关系计算出该记录在表中的存储位置。通常情况下,这种映射关系称作 Hash 函数,而通过 Hash 函数和关键字计算出来的存储位置(注意这里的存储位置只是表中的存储位置,并不是实际的物理地址)称作 Hash 地址。比如上述例子中,假如联系人信息采用 Hash 表存储,则当想要找到“李四”的信息时,直接根据“李四”和 Hash 函数计算出 Hash 地址即可。
hashCode 与 equals 的关系
有人会说,可以直接根据 hashCode 值判断两个对象是否相等吗?肯定是不可以的,因为不同的对象可能会生成相同的 hashCode 值。虽然不能根据 hashCode 值判断两个对象是否相等,但是可以直接根据 hashCode 值判断两个对象不等——如果两个对象的 hashCode 值不等,则必定是两个不同的对象。如果要判断两个对象是否真正相等,必须通过 equals 方法。
也就是说,对于两个对象:
- 如果调用
equals方法得到的结果为true,则两个对象的 hashCode 值必定相等 - 如果
equals方法得到的结果为false,则两个对象的 hashCode 值不一定不同 - 如果两个对象的 hashCode 值不等,则
equals方法得到的结果必定为false - 如果两个对象的 hashCode 值相等,则
equals方法得到的结果未知
哈希表的优点与局限
哈希表可以提供快速的插入操作和查找操作。不论哈希表中有多少数据,插入和删除(有时包括查找)只需要接近常量的时间,即 O(1) 的时间级,实际上只需要几条机器指令。
哈希表运算得非常快,在计算机程序中,如果需要在一秒钟内查找上千条记录,通常使用哈希表(例如拼写检查器),速度明显比树快——树的操作通常需要 O(N) 的时间级。哈希表不仅速度快,编程实现也相对容易。
哈希表也有一些缺点:它是基于数组的,数组创建后难于扩展,某些哈希表被基本填满时,性能下降得非常严重,所以程序必须要清楚表中将要存储多少数据(或者准备好定期地把数据转移到更大的哈希表中,这是个费时的过程)。
而且,也没有一种简便的方法可以按任何一种顺序(例如从小到大)遍历表中数据项。如果需要这种能力,就只能选择其他数据结构。
然而,如果不需要有序遍历数据,并且可以提前预测数据量的大小,那么哈希表在速度和易用性方面是无与伦比的。
哈希算法对比
| 算法 | 速度 | 安全性 | 抗冲突 | 主要用途 | 优点 | 缺点 |
|---|---|---|---|---|---|---|
| SipHash-2-4 | 很快 | 高 | 好 | 哈希表,Python 字符串 hash | 快速、安全、防攻击 | 需要密钥 |
| MD5 | 中等 | 低 | 差 | 文件校验(已不推荐) | 广泛支持 | 易被攻击、冲突多 |
| SHA-1 | 慢 | 中等 | 中等 | Git(正在淘汰) | 曾经的标准 | 已被破解、速度慢 |
| SHA-256 | 慢 | 很高 | 很好 | 密码学、区块链 | 非常安全 | 速度慢、不适合哈希表 |
| djb2 | 很快 | 低 | 一般 | 简单哈希表 | 极快、简单 | 不安全、易被攻击 |
哈希洪水攻击
哈希洪水攻击(hash flooding)指攻击者故意构造大量具有相同哈希值的字符串:
- 导致哈希表退化成链表,性能从 O(1) 降到 O(n)
- 可能让服务器因为处理这些数据而变慢甚至崩溃
维护记录
| 时间 | 修改内容 | 原因 |
|---|---|---|
| 2026-07-04 | 分类由 Linux 改为 language;标题改为含英文的语义化标题;正文拆分为规范的二级标题;哈希算法对比转为 Markdown 表格,洪水攻击说明转为标准列表;统一全角/半角标点与 O(1) 写法;补充 lastmod 与技术标签;开头补充 java.util.Hashtable 的历史版本与现状说明 |
原文分类错误、缺少 lastmod,正文为纯文本排版且标点不统一,不符合 Markdown 规范;缺少 Hashtable 在 Java 中的版本背景与现状说明 |