一篇文章带你彻底搞懂 Java 集合框架(List/Set/Map)

📅 2026/6/20 19:52:10
一篇文章带你彻底搞懂 Java 集合框架(List/Set/Map)
前言集合是 Java 开发每日必用的数据容器不管是接口接收参数、业务数据存储、结果去重、键值映射都离不开 List、Set、Map。 但绝大多数开发者只会调用add()、get()、put()对底层存储结构、扩容逻辑、哈希冲突、线程安全一知半解线上频繁出现内存溢出、查询缓慢、数据重复、并发丢数据等问题。 本文搭配体系结构图、对比表格、底层源码拆解一次性吃透 Java 集合全体系同时覆盖面试高频考点看完既能应对八股面试也能规范业务开发选型。一、集合框架完整体系梳理Java 集合分为两大根接口Collection单列集合、Map双列键值集合。Collection单列存单个元素List有序、可重复、支持索引实现类ArrayList、LinkedList、VectorSet无序、不可重复实现类HashSet、TreeSet、LinkedHashSetQueue队列先进先出实现类ArrayDeque、PriorityQueueMap双列键值对 key-valueHashMap无序键值存储哈希表实现TreeMap按键排序LinkedHashMap插入有序 HashMapHashTable老旧线程安全 Map不推荐使用上图完整展示接口继承、实现类层级关系区分 List/Set/Map 三大分支是学习集合的基础面试常让手绘该结构图。二、ArrayList vs LinkedList 底层结构与业务选型2.1 底层存储源码对比ArrayList底层是动态 Object 数组默认初始化容量 10存连续内存java运行transient Object[] elementData; // 存储元素数组 private int size; // 当前元素数量 // 扩容机制扩容至原容量1.5倍 private void grow(int minCapacity) { int oldCapacity elementData.length; int newCapacity oldCapacity (oldCapacity 1); }扩容流程新增元素超出数组长度 → 创建 1.5 倍长度新数组 →System.arraycopy拷贝全部元素频繁扩容会产生大量数组拷贝损耗性能。LinkedList底层是双向链表无数组、无扩容概念每个节点存前驱、后继指针java运行private static class NodeE { E item; NodeE next; // 下一个节点 NodeE prev; // 上一个节点 }元素分散在堆内存无连续地址依靠指针串联。2.2 核心性能对比表表格特性ArrayListLinkedList底层结构动态数组双向链表随机 get 查询O (1)直接数组下标寻址O (n)需从头遍历节点头部插入删除O (n)数组全部元素后移O (1)仅修改前后节点指针尾部追加O (1)不触发扩容O(1)内存占用紧凑连续内存开销小每个节点额外存两个指针内存开销大遍历效率for 循环、Iterator 效率极高不推荐普通 for 循环只能用迭代器2.3 业务选型规范90% 日常业务优先ArrayList绝大多数场景都是尾部新增、根据索引查询仅高频头部 / 中间插入删除、数据量超大时选用LinkedList固定长度数据可使用Arrays.asList或手动初始化容量减少 ArrayList 扩容次数。三、HashSet 去重原理与 equals/hashCode 强制约定3.1 HashSet 底层本质HashSet底层完全依赖HashMap实现存入元素作为 HashMap 的 keyvalue 统一为静态空 Objectjava运行public HashSet() { map new HashMap(); } public boolean add(E e) { return map.put(e, PRESENT)null; }所以 HashSet 去重逻辑完全复用 HashMap 的 key 判重规则。3.2 去重判断两步流程调用对象hashCode()计算哈希值定位哈希桶若桶内无元素 → 直接存入若桶内已有元素调用equals()对比内容equals 返回 true判定为重复不存入equals 返回 false哈希冲突链表 / 红黑树追加节点。3.3 开发强制规范面试必考题自定义实体存入 HashSet必须同时重写hashCode()与equals()缺一不可只重写 equals、不重写 hashCode相同内容对象哈希值不同判定为两个对象无法去重只重写 hashCode、不重写 equals不同内容可能哈希值碰撞错误判定重复错误示例java运行class User { String id; // 仅重写equals未重写hashCode Override public boolean equals(Object o) { if (this o) return true; User user (User) o; return Objects.equals(id, user.id); } } // 两个id相同的User对象hashCode不同HashSet会同时存储去重失效四、HashMap 工作原理全文核心重点4.1 底层存储结构JDK1.8 优化主体NodeK,V[] table哈希数组哈希桶哈希冲突少时桶内元素用单向链表存储链表长度≥8 且 数组容量≥64链表转为红黑树查询时间复杂度从 O (n) 降至 O (logn)红黑树节点数量≤6退化为链表。4.2 put 插入完整流程计算 key 哈希值hash (key.hashCode()) ^ (hash 16)高低位混合减少冲突通过hash (table.length - 1)计算数组下标判断哈希桶是否为空为空直接新建 Node 放入桶不为空对比桶首节点 keyhash 相等 ( 或 equals) → 覆盖旧 valuekey 不匹配判断当前桶是红黑树还是链表红黑树树内查找 key存在则覆盖不存在新增树节点链表循环遍历链表找到相同 key 覆盖末尾追加新节点追加后链表长度达到 8触发树化插入完成size 自增若size 阈值(容量*0.75)触发 2 倍扩容。4.3 关键参数详解默认初始容量16容量永远是 2 的幂次方方便位运算取模负载因子 0.75达到容量 75% 时扩容平衡哈希冲突与内存占用树化阈值 8、退化阈值 6扩容规则容量翻倍重新计算所有元素哈希下标元素分为高低两条链表迁移。4.4 开发避坑点预估数据量时初始化 HashMap 指定容量new HashMap(预估数量/0.75 1)避免多次扩容自定义对象作为 key必须重写 hashCode 与 equalsHashMap 非线程安全并发场景使用ConcurrentHashMap禁止手动加锁 HashMap。五、集合遍历的 5 种方式、优缺点与使用场景5.1 普通 for 循环仅 List 可用java运行ArrayListString list new ArrayList(); for(int i 0; i list.size(); i){ String s list.get(i); }优点可获取索引、支持遍历中修改元素 缺点LinkedList 使用该方式效率极低每次 get 都从头遍历。5.2 增强 for 循环foreach全部集合通用java运行for(String s : list){ System.out.println(s); }底层依赖迭代器 Iterator语法简洁 坑遍历中调用集合add/remove会触发ConcurrentModificationException并发修改异常。5.3 Iterator 迭代器通用支持安全删除java运行IteratorString it list.iterator(); while(it.hasNext()){ String s it.next(); it.remove(); // 迭代器自身删除方法不会报并发异常 }适用遍历过程中需要删除元素的场景。5.4 ListIterator仅 List 独有可前后遍历java运行ListIteratorString lit list.listIterator(); while(lit.hasNext()){} while(lit.hasPrevious()){} // 反向遍历适合需要双向遍历 List 的特殊业务。5.5 Java8 Stream 流式遍历java运行list.stream().forEach(System.out::println); // 并行流大数据处理 list.parallelStream().filter(s-s.length()1).collect(Collectors.toList());优点支持过滤、映射、分组、并行处理函数式编程简化代码 缺点复杂逻辑可读性下降并行流注意线程安全问题。遍历选型总结ArrayList 需要索引操作普通 for 循环简单遍历、无需增删foreach 增强 for遍历过程删除元素Iterator 迭代器数据过滤、转换、分组、大数据并行Stream 流LinkedList 禁止使用普通 for 循环。六、集合高频开发总结 面试考点List随机查询选 ArrayList频繁中间插入删除选 LinkedListSet 去重核心依赖 hashCodeequals自定义实体必须两个方法一起重写HashMap 核心数组 链表 红黑树、put 完整流程、2 倍扩容、负载因子 0.75并发使用 ConcurrentHashMap遍历规避并发修改异常遍历增删元素只用 Iterator.remove ()所有集合非线程安全Vector/HashTable 除外性能差不推荐多线程场景选用 JUC 并发容器。结尾Java 集合框架是后端面试第一高频模块底层数组、链表、哈希、红黑树逻辑贯穿性能优化、线上故障排查。熟练掌握底层原理后后续缓存、中间件底层哈希结构都能快速理解。