Java 面试题›Java 集合面试题›HashMap 的 remove 方法是如何实现的?
面试考察点
源码理解深度:面试官不仅仅是想知道 “调用 remove 删除元素” 这个表面行为,更是想知道你是否理解底层的删除逻辑,包括链表节点删除、红黑树节点删除、以及退树化条件。
数据结构掌握:考察你是否了解链表删除(指针操作)和红黑树删除(复杂旋转和变色)的区别,以及为什么红黑树删除更复杂。
边界条件意识:是否考虑删除头节点、尾节点、中间节点的不同处理,以及删除后是否需要退树化。
核心答案HashMap 的 remove() 方法核心流程:定位桶 → 遍历查找 → 删除节点 → 更新指针/重构树 → 返回旧值。
删除场景
数据结构
操作方式
时间复杂度
桶为空
-
直接返回 null
O(1)
单节点
链表
桶直接置 null
O(1)
链表头节点
链表
桶指向 next
O(1)
链表中间/尾部
链表
前驱节点.next = 当前.next
O(n)
红黑树节点
红黑树
删除 + 旋转/变色
O(log n)
...
Java 面试题›Java 集合面试题›HashMap 用在并发场景中会出现什么问题?
面试考察点
线程安全意识:面试官不仅仅是想知道 “HashMap 不安全” 这个结论,更是想知道你是否理解具体的并发问题类型(死循环、数据丢失、脏读等),以及这些问题在不同 JDK 版本中的差异。
源码理解深度:考察你是否了解 JDK 1.7 头插法导致的死循环根因,以及 JDK 1.8 尾插法为什么 “只是” 数据丢失而不是死循环。
解决方案掌握:是否知道 ConcurrentHashMap、Collections.synchronizedMap() 等替代方案,以及它们的适用场景。
核心答案HashMap 是非线程安全的,在并发场景下会出现以下问题: **** **** **** **** ****
问题类型
JDK 1.7
JDK 1.8
严重程度
死循环(CPU 100%)
✅ 会发生
❌ 已修复
⚠️⚠️⚠️ 致命
数据丢失
✅ 会发生
✅ 会发生
⚠️⚠️ 严重
数据覆盖
✅ 会发生
✅ 会发生
⚠️⚠ ...
Java 面试题›Java 集合面试题›为什么在 JDK 8 中 HashMap 要转成红黑树?
面试考察点
性能优化意识:面试官不仅仅是想知道 “用了红黑树” 这个事实,更是想知道你是否理解链表查询 O(n) 的性能瓶颈,以及红黑树 O(log n) 的优化意义。
数据结构掌握:考察你是否了解红黑树的特点(自平衡、查询效率稳定),以及为什么选择红黑树而不是 AVL 树或 B+ 树。
安全防护认知:是否了解 HashDoS 攻击(恶意构造哈希冲突),以及红黑树如何作为防御手段。
核心答案JDK 8 引入红黑树是为了 解决极端哈希冲突情况下链表查询性能退化的问题,将查询复杂度从 O(n) 优化到 O(log n): **** **** **** **** ****
对比项
链表
红黑树
查询复杂度
O(n)
O(log n)
插入复杂度
O(1)(头插/尾插)
O(log n)
空间开销
每节点 1 个 next 指针
每节点 left、right、parent、color
适用场景
数据量小、冲突 ...
Java 面试题›Java 集合面试题›为什么 HashMap 的默认负载因子要设置成 0.75?
面试考察点
设计理解深度:面试官不仅仅是想知道 “0.75” 这个数字,更是想知道你是否理解这个数值背后时间和空间的权衡思想,以及 Hash 冲突概率与负载因子的关系。
数学原理认知:考察你是否了解 0.75 与泊松分布的关系,以及为什么这个值能让哈希桶长度超过 8 的概率极低(约千万分之一)。
调优意识:如果你只知道默认值但不知道何时该调整,说明对 HashMap 的理解还停留在 “会用” 层面。
核心答案0.75 是 空间利用率 和 查询效率 之间的最佳平衡点,这个值来自数学上的权衡分析: **** **** **** ****
角度
说明
空间换时间
负载因子越小,空间浪费越多,但哈希冲突越少,查询越快
时间换空间
负载因子越大,空间利用率越高,但哈希冲突越多,查询越慢
泊松分布
0.75 时,链表长度 ≥ 8 的概率约千万分之一,正好是转红黑树的阈值
历史经验
0.75 是经过大量实践验证的经验值,在大多数场景下表现 ...
Java 面试题›Java 集合面试题›说说 HashMap 的扩容机制?如何扩容的?
面试考察点
基础掌握度:面试官不仅仅是想知道 “会扩容” 这个事实,更是想知道你是否理解扩容的触发条件、扩容阈值计算、以及扩容时元素如何重新分布。
源码理解深度:考察你是否读过 resize() 方法的源码,是否理解 JDK 1.8 中 “高低位链表” 的优化设计,以及为什么扩容后元素要么在原位置,要么在 “原位置 + 原容量” 的位置。
版本演进意识:JDK 1.7 和 JDK 1.8 的扩容机制有显著差异(头插法 vs 尾插法),考察你是否了解这些变化以及背后的原因(死循环问题)。
核心答案HashMap 的扩容机制可以概括为:当元素数量超过 容量 × 负载因子 时,容量翻倍,并重新分配所有元素。 **** **** **** **** **** ****
关键点
说明
默认初始容量
16
默认负载因子
0.75
扩容阈值
capacity × loadFactor(首次为 12 = 16 × 0.75)
扩容 ...
Java 面试题›Java 集合面试题›Java 中的集合类有哪些?如何分类的?
面试考察点
体系结构认知:面试官不仅仅想知道你能背出几个集合类名,更想考察你是否理解 Java 集合框架的整体设计思想,能否从接口到实现有一个清晰的层次认知。
选型能力:考察你是否了解不同集合类的特性差异,能否根据实际场景(有序、唯一、排序、线程安全等)选择合适的实现类。
深度与广度:这道题是 “开门题”,面试官通常会根据你的回答深入追问某个具体集合的原理,比如 HashMap 的扩容机制、ConcurrentHashMap 的线程安全实现等。
核心答案Java 集合框架主要分为 两大体系:Collection 和 Map。
flowchart TB
ROOT["Java 集合框架体系"] --> C["Collection(单列)"]
ROOT --> M["Map(双列):Key-Value 键值对存储<br/>HashMap / TreeMap / LinkedHas ...
Java 面试题›Java 集合面试题›HashMap、Hashtable 和 ConcurrentHashMap 的区别?
面试考察点
线程安全认知:面试官不仅仅是想知道这三者谁是线程安全的,更是想考察你是否理解不同线程安全实现方式的性能差异,以及为什么 Hashtable 已经被淘汰。
并发编程深度:考察你是否了解 ConcurrentHashMap 的底层实现原理,包括 JDK 7 的分段锁和 JDK 8 的 CAS + synchronized 两种方案的演进。
生产实践能力:能否根据实际场景(读多写少、高并发等)选择合适的 Map 实现,避免盲目使用导致的性能问题或线程安全隐患。
核心答案三者都是 Map 接口的实现类,但线程安全性和性能差异显著:
特性
HashMap
Hashtable
ConcurrentHashMap
线程安全
❌ 不安全
✅ 安全
✅ 安全
锁粒度
无锁
整表锁(粗粒度)
桶级别锁(细粒度)
null 键/值
✅ 都允许
❌ 都不允许
❌ 都不允许
初始容量
16
11
16
扩容倍数
2 倍
2n + 1
...
Java 面试题›Java 集合面试题›ArrayList、LinkedList 与 Vector 的区别?
面试考察点
集合框架基础:面试官不仅仅想知道你能说出这三者的区别,更想考察你是否理解 List 接口的不同实现方式及其底层原理,包括数组与链表的本质差异。
性能敏感度:考察你是否清楚不同场景下的性能表现,能否根据实际业务需求(查询多还是增删多)选择合适的数据结构。
线程安全意识:Vector 作为线程安全的集合,面试官想了解你是否知道它的实现方式以及为什么在实际开发中很少使用。
核心答案三者都实现了 List 接口,但底层实现和特性差异明显:
特性
ArrayList
LinkedList
Vector
底层结构
动态数组
双向链表
动态数组
线程安全
❌ 不安全
❌ 不安全
✅ 安全(synchronized)
默认容量
10
无(链表无容量概念)
10
扩容机制
1.5 倍
无需扩容
2 倍
随机访问
O(1) 快
O(n) 慢
O(1) 快
头部插入/删除
O(n) 慢
O(1) 快
O(n) 慢
内存占用
连续内存,较少 ...
Java 面试题›Java 基础面试题›为什么不能用 BigDecimal 的 equals 方法做等值比较?
面试考察点
API 理解深度:面试官不仅仅是想知道 “不能用”,更是想考察你是否读过 BigDecimal 的源码,理解 equals() 和 compareTo() 的实现差异。
精度意识:BigDecimal 的核心特性是精度可控,这个问题考察你是否理解 scale(标度)的概念及其对比较的影响。
实战经验:金额比较是金融场景的高频操作,用错方法会导致严重的业务 bug,这反映你的工程经验。
核心答案BigDecimal 的 equals() 方法不仅比较数值,还比较精度,导致 1.0 和 1.00 被判定为不相等。比较 BigDecimal 的数值应该使用 compareTo() 方法。 ****
比较方法
比较内容
1.0 vs 1.00 结果
推荐场景
equals()
数值 + 精度
false(不相等)
❌ 不推荐用于数值比较
compareTo()
仅数值
0(相等)
✅ 数值比较首选
compa ...
Java 面试题›Java 基础面试题›Java 中异常分哪两类,有什么区别?
面试考察点
体系理解:面试官不仅仅是想知道 “受检异常” 和 “非受检异常” 这两个名词,更是想考察你是否理解 Java 异常体系的继承结构(Throwable → Error/Exception)。
编译机制:受检异常的 “受检” 是什么意思?这涉及 Java 编译器如何强制处理异常。
实践能力:实际开发中如何选择异常类型?何时用受检异常、何时用非受检异常?
核心答案Java 异常分为受检异常和非受检异常两大类。受检异常必须显式处理(try-catch 或 throws),否则编译不通过;非受检异常可以不处理,由 JVM 在运行时抛出。
对比维度
受检异常
非受检异常
父类
Exception(除 RuntimeException)
Error、RuntimeException
编译检查
✅ 必须处理,否则编译失败
❌ 不强制处理
处理方式
try-catch 或 throws
可选处理
代表场景
IO 错误、数据库异常
空指针、数组越界、内存溢出
设计理念
可恢 ...
