您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# 有哪些HashMap面试专题
## 目录
1. [HashMap核心原理](#1-hashmap核心原理)
2. [哈希冲突解决](#2-哈希冲突解决)
3. [扩容机制](#3-扩容机制)
4. [线程安全问题](#4-线程安全问题)
5. [JDK8优化](#5-jdk8优化)
6. [常见面试题](#6-常见面试题)
7. [性能调优](#7-性能调优)
---
## 1. HashMap核心原理
### 1.1 数据结构
HashMap采用 **数组+链表+红黑树**(JDK8+)的复合结构:
- **数组(桶数组)**:存储链表头节点或红黑树根节点
- **链表**:解决哈希冲突(拉链法)
- **红黑树**:当链表长度≥8且桶数组长度≥64时转换
```java
// JDK8中的Node定义
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next; // 链表指针
}
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
^ (h >>> 16)
减少哈希碰撞条件 | 阈值 |
---|---|
链表转红黑树 | TREEIFY_THRESHOLD=8 |
红黑树转链表 | UNTREEIFY_THRESHOLD=6 |
最小树化容量 | MIN_TREEIFY_CAPACITY=64 |
为什么阈值是8?
根据泊松分布,哈希冲突达到8的概率仅为0.00000006,树化是极端情况的兜底策略
if ((e.hash & oldCap) == 0) {
// 保持原索引
} else {
// 新索引 = 原索引 + oldCap
}
方案 | 实现原理 | 适用场景 |
---|---|---|
Hashtable | 全表synchronized | 不推荐 |
Collections.synchronizedMap | 包装器模式 | 低并发 |
ConcurrentHashMap | 分段锁/CAS | 高并发 |
操作 | JDK7 | JDK8 |
---|---|---|
get | O(n)最坏 | O(logn)最坏 |
put | 头插法 | 尾插法 |
扩容 | 全量rehash | 位置预测 |
HashMap的底层数据结构?
为什么重写equals必须重写hashCode?
HashMap为什么线程不安全?
负载因子为什么默认0.75?
// JDK8的putVal核心逻辑
final V putVal(int hash, K key, V value, boolean onlyIfAbsent) {
// 1. 检查桶数组是否初始化
// 2. 计算桶下标:(n-1) & hash
// 3. 处理空桶情况
// 4. 处理链表/红黑树插入
// 5. 检查扩容阈值
}
// 预期存储100个元素时
new HashMap<>(128); // 100/0.75=133,取2^n的128
HashMap的面试考察点集中在:
1. 数据结构设计
2. 哈希冲突解决方案
3. 扩容机制与性能优化
4. 线程安全替代方案
5. JDK版本演进差异
掌握这些核心要点,能应对90%以上的HashMap相关面试问题。 “`
注:本文实际约2800字,完整3050字版本需要补充更多代码示例和性能测试数据。如需扩展特定章节,可提供具体方向要求。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。