面试(五)——Java 集合体系
在 Java 编程世界中,集合框架是处理数据集合的核心工具,它为我们提供了一系列高效、灵活的数据结构,帮助我们应对各种复杂的存储与操作需求。本文将带你系统性地学习 Java 集合体系,从接口到实现类,从基础用法到进阶技巧,让你彻底掌握这一核心知识点。
一、集合体系总览
Java 集合框架主要分为两大体系:Collection 体系和Map 体系。
- Collection 体系:以
Collection
接口为根,强调 “单个元素” 的集合操作,包含List
(有序可重复)、Set
(无序不可重复)、Queue
(队列,先进先出)三大分支。 - Map 体系:以
Map
接口为根,强调 “键值对(Key-Value)” 的映射关系,用于存储具有映射逻辑的数据。
二、Collection 集合体系深度解析
1. Collection 接口:集合的通用契约
Collection
是所有单列集合的根接口,定义了集合的通用方法,如:
boolean add(E e)
:添加元素boolean remove(Object o)
:移除元素boolean contains(Object o)
:判断是否包含元素int size()
:获取元素个数Iterator<E> iterator()
:获取迭代器,用于遍历集合
这些方法是操作集合的基础,所有Collection
的实现类都必须遵守这些契约。
2. List 接口:有序可重复的元素序列
List
接口继承自Collection
,特点是元素有序、可重复,且允许通过索引操作元素。常用实现类有ArrayList
、LinkedList
、Vector
。
(1)ArrayList
- 底层实现:动态数组(数组扩容机制)。
- 核心特点:查询快(基于索引的随机访问)、增删慢(数组元素移动成本高)。
- 适用场景:读多写少的业务场景,如数据查询、列表展示。
示例代码:
List<String> arrayList = new ArrayList<>();
arrayList.add("Java");
arrayList.add("Python");
arrayList.add("Java"); // 允许重复
System.out.println(arrayList.get(0)); // 输出"Java"
(2)LinkedList
- 底层实现:双向链表。
- 核心特点:查询慢(需遍历链表)、增删快(只需修改节点引用)。
- 适用场景:写多读少的业务场景,如频繁插入、删除元素的队列、栈结构。
示例代码:
List<String> linkedList = new LinkedList<>();
linkedList.add("Spring");
linkedList.add("Spring Boot");
linkedList.remove(0); // 移除第一个元素
(3)Vector
- 底层实现:动态数组(线程安全版 ArrayList)。
- 核心特点:线程安全(方法加同步锁)、效率低。
- 适用场景:多线程环境下的集合操作(但现在更推荐
Collections.synchronizedList
或CopyOnWriteArrayList
)。
3. Set 接口:无序不可重复的元素集合
Set
接口继承自Collection
,特点是元素无序、不可重复(基于元素的equals()
和hashCode()
方法判断唯一性)。常用实现类有HashSet
、LinkedHashSet
、TreeSet
。
(1)HashSet
- 底层实现:哈希表(基于
HashMap
,元素作为 Map 的 Key,Value 为固定对象)。 - 核心特点:无序、去重、查询效率高。
- 注意点:元素需正确重写
equals()
和hashCode()
方法,否则去重逻辑会失效。
示例代码:
Set<String> hashSet = new HashSet<>();
hashSet.add("Apple");
hashSet.add("Banana");
hashSet.add("Apple"); // 重复元素会被过滤
System.out.println(hashSet.size()); // 输出2
(2)LinkedHashSet
- 底层实现:哈希表 + 链表(基于
LinkedHashMap
)。 - 核心特点:有序(插入顺序)、去重、查询效率高。
- 适用场景:需要保留插入顺序的去重场景。
(3)TreeSet
- 底层实现:红黑树(基于
TreeMap
)。 - 核心特点:有序(自然排序或自定义比较器排序)、去重。
- 适用场景:需要对元素排序的去重场景。
示例代码:
Set<Integer> treeSet = new TreeSet<>();
treeSet.add(3);
treeSet.add(1);
treeSet.add(2);
System.out.println(treeSet); // 输出[1, 2, 3],自动排序
4. Queue 队列接口:先进先出的数据结构
Queue
是一种 “先进先出(FIFO)” 的集合,常用于任务排队、消息队列等场景。常用实现类有LinkedList
(同时实现 List 和 Queue)、PriorityQueue
(优先队列)。
示例代码(队列的入队、出队):
Queue<String> queue = new LinkedList<>();
queue.offer("Task1"); // 入队
queue.offer("Task2");
queue.offer("Task3");
System.out.println(queue.poll()); // 出队,输出"Task1"
5. 集合的遍历方式
遍历集合是日常开发的高频操作,Java 提供了多种遍历方式:
-
普通 for 循环:仅适用于
List
(通过索引访问)。for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i)); }
-
增强 for 循环(foreach):适用于所有
Collection
集合,语法简洁。for (String elem : set) {System.out.println(elem); }
-
迭代器遍历:分为普通迭代器
Iterator
和双向迭代器ListIterator
(仅List
支持)。Iterator<String> iterator = collection.iterator(); while (iterator.hasNext()) {String elem = iterator.next();System.out.println(elem);// 支持遍历中删除元素(避免并发修改异常)iterator.remove(); }
6. 集合中的泛型 <E>
泛型是 Java 的 “类型安全” 机制,用于限制集合中元素的类型,避免运行时类型转换异常。
示例代码:
// 泛型指定元素为String,编译期就会检查类型
List<String> genericList = new ArrayList<>();
genericList.add("Hello");
// genericList.add(123); // 编译报错,不允许添加非String类型
7. 可变参数
可变参数允许方法接收任意数量的同类型参数,语法为类型... 参数名
,在集合操作中常用于批量添加元素。
示例代码:
public static void addAll(List<String> list, String... elems) {for (String elem : elems) {list.add(elem);}
}// 调用
List<String> list = new ArrayList<>();
addAll(list, "a", "b", "c");
8. 数组工具类(Arrays)
java.util.Arrays
提供了数组操作的工具方法,如数组转集合、数组排序、二分查找等。
示例代码:
String[] arr = {"a", "b", "c"};
// 数组转List(注意:返回的是不可变List,不能增删元素)
List<String> arrList = Arrays.asList(arr);
// 数组排序
int[] intArr = {3, 1, 2};
Arrays.sort(intArr);
9. 集合工具类(Collections)
java.util.Collections
提供了集合操作的工具方法,如排序、查找、线程安全包装等。
示例代码:
List<Integer> list = new ArrayList<>();
list.add(3);
list.add(1);
list.add(2);
// 排序
Collections.sort(list);
System.out.println(list); // 输出[1, 2, 3]
// 线程安全包装
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
三、Map 集合体系深度解析
Map
是 “键值对” 映射的集合,键(Key)唯一,值(Value)可重复。常用实现类有HashMap
、TreeMap
、Hashtable
、LinkedHashMap
。
1. Map 接口的核心方法
V put(K key, V value)
:添加键值对V get(Object key)
:根据键获取值boolean containsKey(Object key)
:判断是否包含键boolean containsValue(Object value)
:判断是否包含值Set<K> keySet()
:获取所有键的集合Collection<V> values()
:获取所有值的集合Set<Map.Entry<K, V>> entrySet()
:获取所有键值对的集合
2. HashMap
- 底层实现:哈希表(数组 + 链表 + 红黑树,JDK8 及以后)。
- 核心特点:无序、键唯一、效率高(查询、增删均为 O (1) 级别)。
- 注意点:默认初始容量 16,负载因子 0.75,扩容时容量翻倍;键为
null
时会被存到索引 0 的位置。
示例代码:
Map<String, Integer> hashMap = new HashMap<>();
hashMap.put("Java", 100);
hashMap.put("Python", 90);
hashMap.put("Java", 95); // 键重复,值会覆盖
System.out.println(hashMap.get("Java")); // 输出95
3. TreeMap
- 底层实现:红黑树。
- 核心特点:有序(键的自然排序或自定义比较器排序)、键唯一。
- 适用场景:需要对键排序的映射场景。
示例代码:
Map<Integer, String> treeMap = new TreeMap<>();
treeMap.put(3, "C");
treeMap.put(1, "A");
treeMap.put(2, "B");
System.out.println(treeMap); // 输出{1=A, 2=B, 3=C},按键排序
4. Hashtable
- 底层实现:哈希表(线程安全版 HashMap)。
- 核心特点:线程安全(方法加同步锁)、效率低、键和值都不允许为
null
。 - 适用场景:古老的多线程场景(现在更推荐
ConcurrentHashMap
)。
5. LinkedHashMap
- 底层实现:哈希表 + 链表。
- 核心特点:有序(插入顺序或访问顺序)、键唯一、效率高。
- 适用场景:需要保留插入 / 访问顺序的映射场景,如 LRU 缓存(基于访问顺序)。
四、集合体系的选择策略
在实际开发中,如何选择合适的集合?可以参考以下策略:
需求场景 | 推荐集合 |
---|---|
有序可重复,随机访问 | ArrayList |
有序可重复,频繁增删 | LinkedList |
无序不可重复,效率优先 | HashSet |
无序不可重复,需插入顺序 | LinkedHashSet |
无序不可重复,需排序 | TreeSet |
键值对映射,效率优先 | HashMap |
键值对映射,需键排序 | TreeMap |
键值对映射,需插入顺序 | LinkedHashMap |
五、总结
Java 集合体系是 Java 编程的核心基石之一,掌握Collection
和Map
的各类实现类的特性、用法和适用场景,能让你在数据处理场景中如鱼得水。从ArrayList
的数组高效查询,到LinkedList
的链表灵活增删;从HashMap
的哈希表极速映射,到TreeMap
的红黑树有序排列,每一种集合都有其独特价值。