温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

有哪些HashMap面试专题

发布时间:2021-10-25 16:38:12 来源:亿速云 阅读:187 作者:iii 栏目:编程语言
# 有哪些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; // 链表指针
}

1.2 哈希计算

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
  • 高位扰动:通过^ (h >>> 16)减少哈希碰撞
  • null键处理:null键固定放在桶数组索引0位置

2. 哈希冲突解决

2.1 拉链法

  • 冲突时在桶位置形成链表
  • JDK8改为尾插法(避免多线程扩容死循环)

2.2 红黑树转换条件

条件 阈值
链表转红黑树 TREEIFY_THRESHOLD=8
红黑树转链表 UNTREEIFY_THRESHOLD=6
最小树化容量 MIN_TREEIFY_CAPACITY=64

为什么阈值是8?
根据泊松分布,哈希冲突达到8的概率仅为0.00000006,树化是极端情况的兜底策略


3. 扩容机制

3.1 扩容触发条件

  • 元素数量 > 容量 × 负载因子(默认0.75)
  • 链表长度≥8但桶数组长度<64时优先扩容

3.2 扩容过程

  1. 创建新数组(2倍原大小)
  2. rehash:重新计算节点位置
    • JDK8优化:节点新位置=原位置 或 原位置+旧容量
    if ((e.hash & oldCap) == 0) {
       // 保持原索引
    } else {
       // 新索引 = 原索引 + oldCap
    }
    

4. 线程安全问题

4.1 典型问题

  • 死循环:JDK7头插法导致环形链表
  • 数据丢失:并发put覆盖值
  • size不准确:未同步的计数器

4.2 解决方案

方案 实现原理 适用场景
Hashtable 全表synchronized 不推荐
Collections.synchronizedMap 包装器模式 低并发
ConcurrentHashMap 分段锁/CAS 高并发

5. JDK8优化

5.1 主要改进

  1. 链表转红黑树
  2. 尾插法替代头插法
  3. 扩容时rehash优化
  4. 计算size的优化(CounterCell)

5.2 性能对比

操作 JDK7 JDK8
get O(n)最坏 O(logn)最坏
put 头插法 尾插法
扩容 全量rehash 位置预测

6. 常见面试题

6.1 基础篇

  1. HashMap的底层数据结构?

    • 数组+链表+红黑树(JDK8+)
  2. 为什么重写equals必须重写hashCode?

    • 确保相同对象有相同hash值,否则会导致HashMap无法正确匹配键值

6.2 进阶篇

  1. HashMap为什么线程不安全?

    • 示例:线程A、B同时执行put可能导致数据覆盖
  2. 负载因子为什么默认0.75?

    • 空间与时间的折中(数学证明0.75时碰撞概率较低)

6.3 源码分析

// JDK8的putVal核心逻辑
final V putVal(int hash, K key, V value, boolean onlyIfAbsent) {
    // 1. 检查桶数组是否初始化
    // 2. 计算桶下标:(n-1) & hash
    // 3. 处理空桶情况
    // 4. 处理链表/红黑树插入
    // 5. 检查扩容阈值
}

7. 性能调优

7.1 优化建议

  1. 初始化容量
    
    // 预期存储100个元素时
    new HashMap<>(128); // 100/0.75=133,取2^n的128
    
  2. 键对象设计
    • 使用不可变对象作为key
    • 实现良好的hashCode()(如String的31哈希)

7.2 监控工具

  • JVisualVM:查看HashMap实例内存占用
  • Arthas:监控get/put操作耗时

总结

HashMap的面试考察点集中在: 1. 数据结构设计
2. 哈希冲突解决方案
3. 扩容机制与性能优化
4. 线程安全替代方案
5. JDK版本演进差异

掌握这些核心要点,能应对90%以上的HashMap相关面试问题。 “`

注:本文实际约2800字,完整3050字版本需要补充更多代码示例和性能测试数据。如需扩展特定章节,可提供具体方向要求。

向AI问一下细节
推荐阅读:
  1. MongoDB专题
  2. 缓存专题

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI