当前位置: 首页 > news >正文

【Java工程师面试全攻略】Day2:Java集合框架面试全解析

一、昨日回顾与今日预告

在昨天的开篇文章中,我们了解了Java工程师面试的整体流程和基础准备方向。今天我们将深入Java集合框架,这是面试中出现频率最高的技术点之一。据不完全统计,90%以上的Java技术面试都会涉及集合相关的问题。

二、集合框架整体架构

2.1 Java集合框架类图

Collection
├── List
│   ├── ArrayList
│   ├── LinkedList
│   └── Vector
│       └── Stack
├── Set
│   ├── HashSet
│   │   └── LinkedHashSet
│   └── TreeSet
└── Queue├── PriorityQueue└── Deque└── ArrayDequeMap
├── HashMap
│   └── LinkedHashMap
├── TreeMap
└── Hashtable└── Properties

2.2 核心接口说明

  1. Collection:所有单列集合的根接口
  2. Map:键值对集合的根接口
  3. List:有序、可重复集合
  4. Set:无序、不可重复集合
  5. Queue:队列,FIFO结构

三、List集合深度解析

3.1 ArrayList vs LinkedList

特性ArrayListLinkedList
底层结构动态数组双向链表
随机访问O(1)O(n)
头部插入O(n)O(1)
尾部插入O(1)O(1)
内存占用较少较多(节点开销)
适用场景查询多,增删少增删多,查询少

源码解析:ArrayList扩容机制

// ArrayList的grow方法
private void grow(int minCapacity) {int oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1); // 1.5倍扩容if (newCapacity - minCapacity < 0)newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);elementData = Arrays.copyOf(elementData, newCapacity);
}

3.2 Vector与线程安全

Vector通过synchronized方法保证线程安全,但性能较差。现代Java开发中更推荐使用:

List<String> syncList = Collections.synchronizedList(new ArrayList<>());
// 或者
CopyOnWriteArrayList<String> copyOnWriteList = new CopyOnWriteArrayList<>();

四、Map集合核心剖析

4.1 HashMap实现原理

JDK8的HashMap结构:数组+链表+红黑树

[0] → null
[1] → Node<K,V> → Node<K,V> → TreeNode<K,V>
[2] → null
...
[n] → Node<K,V>

关键参数:

  • 默认初始容量:16
  • 负载因子:0.75
  • 树化阈值:8
  • 退化阈值:6

4.2 HashMap的put方法流程

  1. 计算key的hash值
  2. 如果数组为空,初始化
  3. 计算数组下标:(n-1) & hash
  4. 如果桶为空,直接插入
  5. 如果桶不为空:
    • 键相同则覆盖
    • 如果是树节点,调用树插入
    • 否则遍历链表插入
  6. 判断是否需要树化
  7. 判断是否需要扩容

4.3 ConcurrentHashMap并发控制

JDK8实现改进:

  • 取消分段锁
  • 使用CAS+synchronized
  • 链表长度超过8时转为红黑树
// ConcurrentHashMap的putVal方法片段
final V putVal(K key, V value, boolean onlyIfAbsent) {if (key == null || value == null) throw new NullPointerException();int hash = spread(key.hashCode());int binCount = 0;for (Node<K,V>[] tab = table;;) {Node<K,V> f; int n, i, fh;if (tab == null || (n = tab.length) == 0)tab = initTable(); // 初始化表else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value)))break; // CAS插入}else if ((fh = f.hash) == MOVED)tab = helpTransfer(tab, f); // 协助扩容else {// synchronized锁住链表头节点synchronized (f) {// 链表或树插入操作}}}addCount(1L, binCount);return null;
}

五、高频面试题解析

5.1 问题1:HashMap为什么线程不安全?

参考答案:

  1. 多线程put可能导致元素丢失
  2. 扩容时可能形成循环链表(JDK7)
  3. 并发修改可能导致fast-fail

解决方案:

  • 使用ConcurrentHashMap
  • 使用Collections.synchronizedMap
  • 使用Hashtable(不推荐)

5.2 问题2:ArrayList的迭代器fail-fast机制

List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));Iterator<String> it = list.iterator();
while (it.hasNext()) {String s = it.next();if (s.equals("b")) {list.remove("b"); // 抛出ConcurrentModificationException}
}

解决方案:

  1. 使用迭代器的remove方法
  2. 使用CopyOnWriteArrayList
  3. 使用同步控制

六、实战编码题

题目:实现一个LRU缓存

public class LRUCache<K, V> extends LinkedHashMap<K, V> {private final int capacity;public LRUCache(int capacity) {super(capacity, 0.75f, true);this.capacity = capacity;}@Overrideprotected boolean removeEldestEntry(Map.Entry<K, V> eldest) {return size() > capacity;}public static void main(String[] args) {LRUCache<Integer, String> cache = new LRUCache<>(3);cache.put(1, "A");cache.put(2, "B");cache.put(3, "C");cache.get(1);    // 访问1,使其成为最近使用的cache.put(4, "D"); // 2会被移除System.out.println(cache); // 输出 {3=C, 1=A, 4=D}}
}

七、明日预告

明天我们将探讨《Java并发编程面试精要》,内容包括:

  • 线程生命周期与状态转换
  • synchronized和ReentrantLock的实现原理
  • volatile关键字的内存语义
  • AQS框架与并发工具类
  • 线程池的核心参数与工作原理

八、昨日思考题答案

问题1:final关键字用法

  • final类:不可继承
  • final方法:不可重写
  • final变量:不可修改(基本类型值不可变,引用类型指向不可变)

问题2:Integer缓存问题

Integer a = 100, b = 100;
System.out.println(a == b); // true,使用缓存
Integer c = 200, d = 200;
System.out.println(c == d); // false,超出缓存范围(-128~127)

欢迎继续在评论区交流你的面试经验和问题,我们明天见!

相关文章:

  • 机试 | STL | string | 文字处理软件
  • LVGL显示其他大小的中文
  • word的页眉页脚设置
  • RNN 在时序数据处理中的核心作用
  • 多语言视角下的 DOM 操作:从 JavaScript 到 Python、Java 与 C#
  • 11.10 LangGraph状态管理实战:Reducers模式如何重塑企业级多节点协作?
  • Element UI 对话框固定宽度 + 遮罩层深度定制方案
  • Speech Synthesis/Text to Speech(TTS)
  • Vue2实现Office文档(docx、xlsx、pdf)在线预览
  • TCP 三次握手过程详解
  • JVM GC 分类与原理深度解析
  • 能说一下JVM的内存区域吗
  • Docker系列(四):容器操作全栈指南 —— 从入门到生产级管控
  • MongoDB 快速整合 SpringBoot 示例
  • OpenStack组件:镜像服务(Glance)安装
  • 数据的六个特性以及由于独特性产生的一些有趣的想法
  • Qt qml Network error问题
  • GitLab-CI实现自动化测试
  • 完美解决Docker镜像无法拉取问题(转载)
  • 【学习笔记】GitLab 下载安装与配置
  • 北京做网站多少钱/汕头网站关键词推广
  • 申请建设网站的请示/百度网址大全怎么设为主页
  • 博网站建设/网络营销平台有哪些
  • wordpress app下载模板下载/广州seo
  • 如何做网站内容管理/百度帐号登录入口
  • wordpress 自动tag标签/杭州网站优化效果