文章目录
友情提示:阅读本文前请备好咖啡☕️,防止被哈希碰撞震晕大脑~
🎨 抽象漫画场景

📚 标准技术解析(严肃版)
一、核心数据结构
// 简化结构伪代码
class HashMap {
Node<K,V>[] table; // 数组(桶)
float loadFactor; // 负载因子(默认0.75)
int threshold; // 扩容阈值 = capacity * loadFactor
int modCount; // 结构修改计数器(用于快速失败)
static class Node<K,V> { // 基础节点(链表)
final int hash;
final K key;
V value;
Node<K,V> next;
}
static final class TreeNode<K,V> extends Node<K,V> { // 树节点(Java8+)
TreeNode<K,V> parent, left, right;
boolean red; // 红黑树颜色标记
}
}
二、关键机制
-
哈希计算与索引定位
// 扰动函数(Java 8优化) static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } // 索引计算(n为桶数组长度) int index = (n - 1) & hash; -
链表转树阈值
- 链表长度 ≥ 8 且 桶数组长度 ≥ 64 → 转为红黑树
- 树节点数 ≤ 6 → 退化为链表
-
扩容机制(Rehashing)
newCapacity = oldCapacity << 1; // 容量翻倍 threshold = (int)(newCapacity * loadFactor); // 更新阈值 // 重新计算所有节点位置:index = (newCapacity - 1) & hash -
线程安全问题
- Java 7:头插法扩容可能导致环形链表(死循环)
- Java 8+:尾插法解决死循环,但仍非线程安全(需用ConcurrentHashMap)
🚀 自由发挥:HashMapの奇幻漂流
章节一:哈希寻宝大冒险 🏴☠️
想象你是个海盗,key.hashCode()是藏宝图坐标。但大海太大(32位哈希值范围约42亿),
你的小船(桶数组)只有16个座位(默认容量)。怎么办?
骚操作来了:
- 扰动函数把坐标图撕成两半(
h ^ (h>>>16))再拼起来,让宝藏分布更均匀 - 用
(n-1) & hash魔法卷轴把坐标压缩到小船座位号
举个栗子🌰:
hash = 0xAB12CD34,n=16→
(16-1)=15(二进制1111)
0xAB12CD34 & 1111 = 0100→ 座位4号!
章节二:扩容:HashMapの成长的烦恼 😤
当海盗船塞满12个宝藏(16*0.75=12),系统强制你换豪华游轮(扩容)!
但搬家是痛苦的:
// 伪代码:Java 8扩容核心逻辑
void resize() {
Node<K,V>[] oldTab = table;
int oldCap = oldTab.length;
int newCap = oldCap << 1; // 容量翻倍(说人话:newCap = oldCap * 2)
// 创建新船(数组)
Node<K,V>[] newTab = new Node[newCap];
// 旧船寻宝重新分配
for (Node<K,V> e : oldTab) {
while (e != null) {
// 重新计算座位号:(newCap-1) & hash
int newIndex = ... ;
// 尾插法挂载到新船(Java8不再头插!)
e.next = newTab[newIndex];
newTab[newIndex] = e;
e = e.next;
}
}
table = newTab; // 老船沉没,新船启航!
}
血泪教训:已知宝藏量时,请用new HashMap(128)直接开大船!避免频繁扩容(性能黑洞)!
章节三:红黑树——链表の华丽逆袭 💃
当某个座位挂满8个钥匙(链表长度=8),且整艘船≥64个座位时——
// 链表转树伪代码
void treeifyBin(Node<K,V>[] tab, int hash) {
if (tab.length < 64) {
resize(); // 船太小?先扩容试试!
return;
}
// 链表 → 红黑树(此处省略500行平衡操作代码)
TreeNode root = buildTree(linkedList);
}
为什么选红黑树?
- 链表查找:最坏O(n)(相当于翻遍8把钥匙)
- 红黑树查找:O(log n)(类似二分查找,8个元素最多比3次!)
🤣 程序员的浪漫:当HashMap走进相亲角
public class ProgrammerDate {
public static void main(String[] args) {
Map<Girl, Boolean> heart = new HashMap<>();
Girl alice = new Girl("Alice", 170);
heart.put(alice, true); // 一见钟情
// 重遇整容后的Alice(未重写hashCode/equals)
Girl alice2 = new Girl("Alice", 170);
if (heart.get(alice2) == null) {
System.out.println("你谁啊?我爱的Alice的hashCode是" + alice.hashCode());
} else {
System.out.println("原来是你!我的红玫瑰🌹");
}
}
}
class Girl {
String name;
int height;
// 未重写hashCode和equals...
}
结局:程序员因未重写hashCode/equals孤独终老(手动狗头)🐶
⚠️ 免责声明与求三连
本文内容经多次
DEBUG测试,但作者不保证:
- 阅读后不会在面试中过度炫耀HashMap知识遭面试官嫉妒
- 不会在代码里写
// 此处优化参考了某神文被同事发现- 女朋友不会因为你看红黑树比看她的时间长而生气
觉得有用?
👍点赞暴富 | 📌收藏防身 | ➕关注解锁《ConcurrentHashMapの锁分裂艺术》
(下次一定?这次一定!)

59

被折叠的 条评论
为什么被折叠?



