Java集合框架高频面试题总结
集合框架概述
-
Java集合框架的主要组成部分
- Collection接口
- List: 有序可重复
- Set: 无序不可重复
- Queue: 队列
- Map接口: 键值对存储 -
集合框架的继承体系
- Collection
- List → ArrayList, LinkedList, Vector
- Set → HashSet, LinkedHashSet, TreeSet
- Queue → PriorityQueue, ArrayDeque
- Map → HashMap, LinkedHashMap, TreeMap, Hashtable
List相关
-
ArrayList和Vector的区别
| 特性 | ArrayList | Vector |
|------|-----------|--------|
| 线程安全 | 不安全 | 安全 |
| 扩容 | 1.5倍 | 2倍 |
| 性能 | 高 | 低 |
| 迭代器 | fail-fast | fail-fast | -
ArrayList的扩容机制
- 初始容量10
- 扩容时newCapacity = oldCapacity + (oldCapacity >> 1)
- 使用Arrays.copyOf()复制到新数组 -
LinkedList的实现原理
- 基于双向链表实现
- 节点结构:prev, item, next
- 插入删除O(1),查找O(n)
Set相关
-
HashSet的实现原理
- 基于HashMap实现(使用PRESENT对象作为value)
- 依赖hashCode()和equals()保证元素唯一
- 无序存储 -
LinkedHashSet的特点
- 继承HashSet
- 内部使用LinkedHashMap
- 维护插入顺序的迭代顺序 -
TreeSet的排序方式
- 基于TreeMap实现
- 自然排序(元素实现Comparable)
- 定制排序(传入Comparator)
Map相关
-
HashMap的工作原理
- 数组+链表+红黑树(JDK8+)
- 默认加载因子0.75,初始容量16
- 哈希冲突解决:链表法(>8转红黑树,<6退化为链表) -
HashMap的put方法流程
1. 计算key的hash值
2. 如果数组为空则初始化
3. 计算桶位置:(n-1) & hash
4. 如果桶为空,直接插入
5. 否则处理冲突(链表/红黑树)
6. 如果key存在则覆盖value
7. 判断是否需要扩容 -
HashMap为什么线程不安全
- 多线程put可能导致数据丢失
- JDK7中resize可能导致环形链表
- 使用ConcurrentHashMap保证线程安全 -
HashMap和Hashtable的区别
| 特性 | HashMap | Hashtable |
|------|---------|-----------|
| 线程安全 | 不安全 | 安全 |
| null键值 | 允许 | 不允许 |
| 迭代器 | fail-fast | enumerator |
| 继承 | AbstractMap | Dictionary | -
ConcurrentHashMap的实现原理
- JDK7: 分段锁(Segment)
- JDK8: CAS + synchronized
- Node数组+链表+红黑树
- 并发控制更细粒度
集合工具类
-
Collections工具类常用方法
- sort(): 排序
- shuffle(): 随机打乱
- reverse(): 反转
- synchronizedXxx(): 创建线程安全集合
- unmodifiableXxx(): 创建不可变集合 -
Arrays工具类常用方法
- sort(): 排序
- binarySearch(): 二分查找
- equals(): 比较数组
- fill(): 填充
- asList(): 数组转List(注意返回的是固定大小List)
迭代器
-
fail-fast和fail-safe机制
- fail-fast: 快速失败(ConcurrentModificationException)
- fail-safe: 安全失败(基于克隆,如ConcurrentHashMap)
- 实现原理:modCount计数器 -
Iterator和ListIterator的区别
- ListIterator可以双向遍历
- ListIterator可以修改集合(add/set)
- ListIterator可以获取当前位置
性能比较
-
集合类的选择策略
- 随机访问多:ArrayList
- 增删操作多:LinkedList
- 需要唯一性:HashSet
- 需要排序:TreeSet
- 键值存储:HashMap
- 线程安全:ConcurrentHashMap -
集合的遍历方式比较
- for循环:ArrayList性能好
- 迭代器:通用方式
- forEach:简洁但性能略低
- Stream API:函数式风格
Java 8+新特性
-
Stream API常用操作
- 创建流:stream(), parallelStream()
- 中间操作:filter(), map(), sorted(), distinct()
- 终止操作:forEach(), collect(), reduce() -
Optional的使用场景
- 避免NullPointerException
- orElse(): 提供默认值
- orElseGet(): 延迟提供默认值
- ifPresent(): 值存在时执行操作
高级话题
-
如何设计不可变集合
- 使用Collections.unmodifiableXxx()
- 使用Guava的Immutable集合
- Java 9的List.of(), Set.of(), Map.of() -
深拷贝和浅拷贝在集合中的体现
- 浅拷贝:只复制引用
- 深拷贝:复制对象本身
- 实现方式:序列化/clone方法 -
如何解决Hash冲突
- 开放地址法
- 链地址法(HashMap采用)
- 再哈希法
- 公共溢出区法 -
红黑树的特点
- 自平衡二叉查找树
- 节点是红色或黑色
- 根节点和叶子节点(NIL)是黑色
- 红色节点的子节点必须是黑色
- 从任一节点到其每个叶子的路径包含相同数目的黑色节点
这些集合相关面试题涵盖了Java集合框架的核心知识点,掌握它们可以帮助你在面试中游刃有余。建议结合实际代码示例理解这些概念,并思考它们在不同场景下的应用。