Java集合全家桶|从基础到源码,吃透春招高频考点
目录
② LinkedList(高频,与ArrayList对比必考)
3.2 LinkedHashMap(有序Map,场景化考点)
3.5 ConcurrentHashMap(线程安全Map,高频考点)
一、Java集合核心体系总览(先搭框架,再填细节)
Java集合的核心接口分为两大体系:Collection体系(存储单个元素)和Map体系(存储键值对),二者无继承关系,共同构成Java集合的完整骨架。先记住一句话:Collection管单值,Map管键值,所有实现类都围绕这两大体系展开。
1.1 核心体系结构图(面试口述必备)
Collection体系(单值存储):
Collection → List(有序、可重复):ArrayList、LinkedList、Vector Collection → Set(无序、不可重复):HashSet、LinkedHashSet、TreeSet
Map体系(键值对存储):
Map → HashMap、LinkedHashMap、TreeMap、Hashtable、ConcurrentHashMap
1.2 核心接口核心方法(必记,面试高频提问)
Collection接口(所有单值集合的顶层接口)
-
添加:add(E e)、addAll(Collection<? extends E> c)
-
删除:remove(Object o)、removeAll(Collection<?> c)、clear()
-
查询:size()、isEmpty()、contains(Object o)、iterator()
-
遍历:iterator迭代器、增强for循环(foreach)
Map接口(所有键值对集合的顶层接口)
-
添加:put(K key, V value)、putAll(Map<? extends K, ? extends V> m)
-
删除:remove(Object key)、clear()
-
查询:size()、isEmpty()、containsKey(Object key)、containsValue(Object value)、get(Object key)
-
遍历:keySet()(遍历键)、values()(遍历值)、entrySet()(遍历键值对,最常用)
二、Collection体系详解(重点中的重点)
Collection体系的核心是List和Set,二者的核心区别的是:List有序、可重复,Set无序、不可重复(无序≠随机,具体看实现类)。下面逐个拆解常用实现类,从底层结构、核心特点、使用场景、面试考点四个维度讲解。
2.1 List接口(有序、可重复,日常开发最常用)
List接口的核心优势是“有序”(元素插入顺序=遍历顺序)、“可重复”,支持通过索引访问元素(类似数组,但长度可变),常用实现类:ArrayList、LinkedList、Vector(几乎淘汰)。
① ArrayList(春招高频,重点掌握)
底层结构
基于动态数组(JDK8无初始容量时,默认初始化空数组,第一次add时扩容为10;JDK7及之前默认初始容量10),底层维护一个Object[] elementData数组,通过扩容机制实现长度动态变化。
核心特点
-
查询快:支持通过索引直接访问(O(1)时间复杂度),适合频繁查询的场景;
-
增删慢:增删元素时,需要移动数组元素(如尾部增删快,中间增删慢,时间复杂度O(n));
-
线程不安全:非线程安全,多线程环境下使用会出现并发修改异常(ConcurrentModificationException);
-
扩容机制:当元素个数达到容量的1.5倍时,触发扩容(扩容公式:newCapacity = oldCapacity + (oldCapacity >> 1)),扩容时会拷贝原数组元素到新数组,存在性能开销。
面试高频坑
-
问:ArrayList和数组的区别?答:数组固定长度,ArrayList动态扩容;数组可存储基本类型+引用类型,ArrayList仅能存储引用类型(基本类型会自动装箱);
-
问:ArrayList的扩容机制?答:JDK8默认空数组,第一次add扩容为10,后续每次扩容为原容量的1.5倍,扩容时通过Arrays.copyOf()拷贝元素;
-
问:ArrayList线程不安全,怎么解决?答:① 使用Collections.synchronizedList()包装;② 使用CopyOnWriteArrayList(写时复制,适合读多写少场景);③ 手动加锁(synchronized)。
② LinkedList(高频,与ArrayList对比必考)
底层结构
基于双向链表(JDK1.6及之前是双向循环链表,JDK1.7及之后取消循环,改为普通双向链表),每个节点(Node)包含prev(前驱节点)、item(元素)、next(后继节点)三个属性。
核心特点
-
增删快:增删元素时,只需修改链表节点的指针,无需移动元素(时间复杂度O(1),前提是找到目标节点;若通过索引查找,时间复杂度O(n));
-
查询慢:无索引,查询元素需从链表头/尾遍历,时间复杂度O(n);
-
线程不安全:与ArrayList一样,非线程安全;
-
额外功能:实现了Deque接口,可作为队列、双端队列使用(如addFirst()、addLast()、pollFirst()等方法)。
ArrayList vs LinkedList(面试必考对比)
|
对比维度 |
ArrayList |
LinkedList |
|---|---|---|
|
底层结构 |
动态数组 |
双向链表 |
|
查询效率 |
高(O(1)) |
低(O(n)) |
|
增删效率(中间) |
低(O(n)) |
高(O(1)) |
|
内存占用 |
有扩容冗余(浪费内存) |
无冗余,但每个节点多存两个指针(内存开销略大) |
|
使用场景 |
频繁查询、少量增删 |
频繁增删、少量查询,或作为队列使用 |
③ Vector(淘汰类,面试仅需了解)
底层也是动态数组,与ArrayList几乎一致,但线程安全(所有方法加了synchronized锁),效率极低,现在几乎不使用。面试中常考:Vector和ArrayList的区别(核心是线程安全和效率)。
2.2 Set接口(无序、不可重复,去重场景必备)
Set接口的核心是“不可重复”(元素唯一),“无序”(默认无序,LinkedHashSet除外),底层依赖equals()和hashCode()方法保证元素唯一(面试高频考点),常用实现类:HashSet、LinkedHashSet、TreeSet。
① HashSet(最常用,春招高频)
底层结构
基于HashMap实现(本质是HashMap的key集合,value是一个固定的空对象),底层依赖哈希表(数组+链表/红黑树),JDK8中当链表长度超过8且数组长度≥64时,链表转为红黑树;当链表长度≤6时,红黑树转回链表(优化查询效率)。
核心特点
-
无序:元素存储顺序与插入顺序无关(底层哈希表的哈希值决定存储位置);
-
不可重复:依赖equals()和hashCode(),两个对象hashCode相等且equals返回true,视为同一个元素,无法重复添加;
-
线程不安全:非线程安全,多线程环境下需注意并发问题;
-
查询、增删效率:平均O(1),最坏O(n)(链表未转红黑树时)。
面试高频坑
-
问:HashSet如何保证元素不可重复?答:添加元素时,先计算元素的hashCode(),找到哈希表中的位置;若该位置无元素,直接添加;若有元素,调用equals()比较,相等则不添加,不相等则以链表/红黑树形式存储(哈希冲突解决);
-
问:HashSet的底层为什么是HashMap?答:HashMap的key天然不可重复,HashSet复用HashMap的key存储元素,value用一个固定的Object对象(PRESENT)填充,节省内存;
-
问:自定义对象存入HashSet,需要重写哪些方法?答:必须重写equals()和hashCode(),且遵循“equals相等,hashCode必相等;hashCode相等,equals不一定相等”的原则,否则会导致元素重复存储。
② LinkedHashSet(有序去重,场景化考点)
底层结构
基于LinkedHashMap实现,底层是“哈希表+双向链表”,双向链表用于维护元素的插入顺序,哈希表用于保证元素不可重复。
核心特点
-
有序:元素存储顺序=插入顺序(双向链表维护);
-
不可重复:与HashSet一致,依赖equals()和hashCode();
-
线程不安全:非线程安全;
-
效率:略低于HashSet(多维护了双向链表),但查询、增删仍接近O(1)。
使用场景:需要去重且保留插入顺序的场景(如用户历史记录去重)。
③ TreeSet(排序去重,底层红黑树)
底层结构
基于红黑树(自平衡二叉查找树)实现,底层依赖TreeMap的key集合,核心是“排序+去重”。
核心特点
-
有序:不是插入顺序,而是自然排序(如Integer按数值大小,String按字典序)或自定义排序(实现Comparator接口);
-
不可重复:基于排序规则去重,若两个元素排序后相等,则视为重复元素;
-
线程不安全:非线程安全;
-
效率:查询、增删效率O(log n)(红黑树的特性)。
面试考点:TreeSet的排序方式(自然排序vs自定义排序),底层红黑树的作用(保证排序和查询效率)。
三、Map体系详解(春招重中之重,源码必问)
Map体系存储键值对(key-value),核心特点:key不可重复(唯一),value可重复;key可以为null(HashMap、LinkedHashMap允许,Hashtable、TreeMap不允许),value可以为null。常用实现类:HashMap、LinkedHashMap、TreeMap、Hashtable、ConcurrentHashMap。
3.1 HashMap(最常用,源码高频考点)
HashMap是Map体系的核心实现类,日常开发中使用频率最高,也是面试中源码考察的重点(哈希冲突、扩容机制、红黑树转换等)。
底层结构(JDK8重点)
基于哈希表(数组+链表/红黑树)实现,底层维护一个Node[] table数组(哈希桶),每个Node包含key、value、next(链表指针)、hash(key的哈希值)四个属性。
核心优化(JDK8 vs JDK7):JDK7底层是数组+链表,JDK8引入红黑树,当链表长度超过8且数组长度≥64时,链表转为红黑树;当链表长度≤6时,红黑树转回链表,优化查询效率(从O(n)提升到O(log n))。
核心原理(面试必背)
-
哈希计算:key的hashCode()经过扰动计算(减少哈希冲突),得到hash值,再通过hash & (table.length-1) 计算出元素在数组中的索引位置;
-
哈希冲突解决:当两个key的hash值相同,索引位置一致时,使用链表存储;链表长度达到阈值后转为红黑树;
-
扩容机制:默认初始容量16,负载因子0.75(当元素个数达到16*0.75=12时,触发扩容),每次扩容为原容量的2倍(保证table.length是2的幂,方便通过位运算计算索引);
-
key不可重复:添加元素时,若key的hash值相同且equals返回true,则覆盖原value;否则存入链表/红黑树。
面试高频坑(源码级)
-
问:HashMap的初始容量、负载因子是什么?作用是什么?答:初始容量16,负载因子0.75;负载因子用于控制扩容时机,负载因子越大,哈希冲突概率越高,内存利用率越高;负载因子越小,哈希冲突越少,内存浪费越多;
-
问:JDK8中HashMap为什么引入红黑树?答:解决链表过长导致的查询效率低下问题,将查询时间复杂度从O(n)优化为O(log n);
-
问:HashMap为什么线程不安全?会出现什么问题?答:多线程环境下,扩容时会出现死循环(JDK7)、并发修改异常(JDK8);解决方案:使用ConcurrentHashMap;
-
问:HashMap的key可以为null吗?为什么?答:可以;因为HashMap在计算null的hash值时,默认返回0,存入索引0的位置,且仅允许一个null key(保证key唯一)。
3.2 LinkedHashMap(有序Map,场景化考点)
底层结构
继承自HashMap,底层是“哈希表+双向链表”,双向链表用于维护元素的插入顺序(默认)或访问顺序(可设置),哈希表保证key唯一。
核心特点
-
有序:默认维护插入顺序(插入顺序=遍历顺序),可通过构造方法设置为“访问顺序”(最近访问的元素排在末尾,适合做LRU缓存);
-
其他特性:与HashMap一致(key可null、线程不安全、哈希冲突解决方式等);
-
LRU缓存:通过重写removeEldestEntry()方法,可实现LRU(最近最少使用)缓存(面试常考场景)。
3.3 TreeMap(排序Map,底层红黑树)
底层结构
基于红黑树实现,与TreeSet类似,底层依赖红黑树的排序特性,实现key的有序存储。
核心特点
-
有序:key按自然排序或自定义排序(实现Comparator接口),遍历顺序为排序后的顺序;
-
key不可重复:基于排序规则去重,key不能为null(会抛出NullPointerException);
-
线程不安全:非线程安全;
-
效率:查询、增删效率O(log n)。
3.4 Hashtable(淘汰类,面试对比考点)
底层是哈希表(数组+链表),与HashMap类似,但有两个核心区别:
-
线程安全:所有方法加synchronized锁,效率极低;
-
key/value不可为null:否则抛出NullPointerException;
面试考点:HashMap和Hashtable的区别(核心是线程安全、key/value是否允许null、扩容机制)。
3.5 ConcurrentHashMap(线程安全Map,高频考点)
核心定位
解决HashMap线程不安全、Hashtable效率低的问题,是多线程环境下的首选Map实现类,底层优化(JDK7 vs JDK8)差异较大,面试重点考察JDK8版本。
JDK8底层结构与核心优化
-
底层:哈希表(数组+链表/红黑树),与HashMap结构一致;
-
线程安全实现:放弃JDK7的分段锁(Segment),改用CAS+synchronized(对哈希桶的头节点加锁),粒度更细,效率更高;
-
其他优化:支持并发扩容、key/value可null(与HashMap一致)、查询、增删效率接近HashMap。
面试考点:ConcurrentHashMap的线程安全实现方式(JDK7 vs JDK8)、与Hashtable的区别(锁粒度、效率)。
四、集合高频面试题汇总(春招必背)
结合前面的讲解,整理10道春招高频面试题,直接背答案即可应对大部分面试场景:
-
Java集合体系分为哪两大体系?核心区别是什么?答:Collection(单值存储)和Map(键值对存储);Collection存储单个元素,Map存储key-value键值对,无继承关系。
-
ArrayList和LinkedList的区别?(前面已详细讲解,重点记底层结构、查询/增删效率、使用场景)。
-
HashSet如何保证元素不可重复?答:依赖equals()和hashCode(),添加元素时先计算hashCode,找到索引位置,再用equals比较,相等则不添加,否则存入链表/红黑树。
-
HashMap的底层结构(JDK8)?哈希冲突如何解决?答:底层是数组+链表/红黑树;哈希冲突通过链表存储,链表长度超过8且数组≥64时转为红黑树。
-
HashMap和ConcurrentHashMap的区别?答:HashMap线程不安全,ConcurrentHashMap线程安全(JDK8用CAS+synchronized);ConcurrentHashMap支持并发操作,效率高于Hashtable。
-
TreeSet和HashSet的区别?答:HashSet底层HashMap,无序、不可重复,效率O(1);TreeSet底层红黑树,有序(自然/自定义排序)、不可重复,效率O(log n)。
-
自定义对象存入HashSet/HashMap,需要重写哪些方法?为什么?答:重写equals()和hashCode();保证equals相等的对象,hashCode必相等,避免元素重复存储。
-
ArrayList的扩容机制?答:JDK8默认空数组,第一次add扩容为10,后续每次扩容为原容量的1.5倍,扩容时拷贝原数组元素到新数组。
-
LinkedHashMap如何实现LRU缓存?答:设置访问顺序(构造方法传入accessOrder=true),重写removeEldestEntry()方法,定义缓存容量,当超过容量时删除最久未访问的元素。
-
Collection和Collections的区别?答:Collection是单值集合的顶层接口,定义核心方法;Collections是工具类,提供静态方法(如sort()、synchronizedList()),用于操作集合。
五、总结(
Java集合的学习核心是“先搭体系,再挖细节,结合源码,吃透考点”:
1. 先记住集合体系结构(Collection和Map两大体系),明确每个接口的核心特点(List有序可重复、Set无序不可重复、Map键值对);
2. 重点掌握常用实现类(ArrayList、LinkedList、HashSet、HashMap、ConcurrentHashMap),理解底层结构、核心方法、使用场景;
3. 面试重点准备“对比类”问题(如ArrayList vs LinkedList、HashMap vs Hashtable、HashSet vs TreeSet)和“源码类”问题(HashMap扩容、哈希冲突、ConcurrentHashMap线程安全);
4. 结合代码实操,比如手写ArrayList的简单实现、用LinkedHashMap实现LRU缓存,加深理解。
Java集合是基础中的基础,也是面试的“敲门砖”,只要吃透本文的内容,就能轻松应对集合相关的所有面试题,祝大家顺利,拿到心仪offer!
更多推荐




所有评论(0)