11_Java集合框架概述
Java集合框架概述 —— Collection与Map体系全解析
文章目录
- Java集合框架概述 —— Collection与Map体系全解析
- 前言
- 一、Java集合框架的体系结构
- 二、Collection接口详解
- 2.1 Collection核心方法
- 2.2 List接口
- 2.3 Set接口
- 2.4 Queue接口
- 三、Map接口详解
- 3.1 Map核心方法
- 3.2 HashMap使用示例
- 四、迭代器详解
- 4.1 迭代器的三个核心方法
- 4.2 迭代过程中安全删除元素
- 4.3 增强for循环的本质
- 五、迭代器模式的设计思想
- 设计模式实践
- 六、集合的选择策略
- 总结
- ✅ 亮点总结
- 适用场景
- 扩展方向
前言
在Java开发中,数据的存储与操作是永恒的核心话题。无论是处理用户列表、缓存数据,还是构建复杂的数据结构,都离不开集合框架的支持。Java集合框架(Java Collections Framework,简称JCF)是JDK提供的一套设计精良的数据结构工具库,理解它的体系结构对于写出高效、优雅的Java代码至关重要。
集合框架的核心设计思想是接口与实现分离——所有的集合操作都通过接口(如List、Set、Map)来定义规范,不同的实现类(如ArrayList、LinkedList、HashMap)提供不同的底层数据结构和性能特征。这种设计让你可以在不修改调用代码的情况下切换实现类:比如从ArrayList换成LinkedList,只需修改一行new语句,其余代码保持不变。这种灵活性正是面向接口编程的最佳体现。
本文将带你从整体上把握Java集合框架的体系结构,理解Collection和Map两大接口体系,并掌握迭代器的使用方式。这篇文章是后续ArrayList/LinkedList对比和HashMap深度解析两篇文章的基础铺垫。
一、Java集合框架的体系结构
Java集合框架主要分为两大接口体系:Collection和Map。这个划分非常清晰——Collection是"单列数据"的抽象(一条一条的元素),Map是"键值对数据"的抽象(Key→Value的映射关系)。两者是并列关系而非继承关系——Map不是Collection的子接口,这一点在面试中经常被用来制造陷阱。
- Collection接口:存储单个元素,是List、Set、Queue的父接口
- Map接口:存储键值对(Key-Value),与Collection接口是并列关系
整体继承关系如下:
Collection (接口) ├── List (接口) —— 有序、可重复 │ ├── ArrayList │ ├── LinkedList │ └── Vector (已基本淘汰) ├── Set (接口) —— 无序、不可重复 │ ├── HashSet │ ├── LinkedHashSet │ └── TreeSet └── Queue/Deque (接口) —— 队列/双端队列 ├── LinkedList ├── ArrayDeque └── PriorityQueue Map (接口) —— 键值对 ├── HashMap ├── LinkedHashMap ├── TreeMap └── Hashtable (已基本淘汰)下面通过一个简单的示例来感受不同集合的特点:
importjava.util.*;publicclassCollectionOverview{publicstaticvoidmain(String[]args){// List:有序可重复List<String>list=newArrayList<>();list.add("Java");list.add("Python");list.add("Java");// 允许重复System.out.println("List: "+list);// [Java, Python, Java]// Set:无序不可重复Set<String>set=newHashSet<>();set.add("Java");set.add("Python");set.add("Java");// 重复元素不会添加System.out.println("Set: "+set);// [Java, Python] 或 [Python, Java]// Map:键值对Map<String,Integer>map=newHashMap<>();map.put("Java",1995);map.put("Python",1991);map.put("Java",1996);// 覆盖旧值System.out.println("Map: "+map);// {Java=1996, Python=1991}}}二、Collection接口详解
Collection是List、Set、Queue的最高父接口,定义了集合操作的通用方法。
2.1 Collection核心方法
publicinterfaceCollection<E>extendsIterable<E>{intsize();// 返回元素个数booleanisEmpty();// 判断是否为空booleancontains(Objecto);// 是否包含某元素booleanadd(Ee);// 添加元素booleanremove(Objecto);// 移除元素voidclear();// 清空集合Iterator<E>iterator();// 获取迭代器Object[]toArray();// 转换为数组// ... 还有其他方法}2.2 List接口
List是有序集合,可以通过索引访问元素。核心特点:有序、可重复、有索引。
publicclassListDemo{publicstaticvoidmain(String[]args){List<String>list=newArrayList<>();list.add("A");list.add("B");list.add("C");// 索引访问System.out.println(list.get(1));// B// 在指定位置插入list.add(1,"X");System.out.println(list);// [A, X, B, C]// 遍历方式for(inti=0;i<list.size();i++){System.out.print(list.get(i)+" ");// A X B C}}}2.3 Set接口
Set不允许重复元素,主要用于去重场景。判断重复依赖**equals()和hashCode()**方法。
publicclassSetDemo{publicstaticvoidmain(String[]args){Set<String>set=newHashSet<>();set.add("apple");set.add("banana");set.add("apple");// 不会添加System.out.println(set.size());// 2// TreeSet 实现排序Set<Integer>sortedSet=newTreeSet<>();sortedSet.add(5);sortedSet.add(1);sortedSet.add(3);System.out.println(sortedSet);// [1, 3, 5] 自动排序}}2.4 Queue接口
Queue模拟队列数据结构,遵循FIFO(先进先出)原则。在Java中,Queue是一个接口,LinkedList是它最常用的实现(同时实现了List和Deque)。理解Queue的API设计模式很重要,因为它体现了Java集合框架的一个设计惯例——用不同返回值处理不同错误场景:
| 操作 | 抛出异常 | 返回特殊值 |
|---|---|---|
| 入队 | add(e) | offer(e)→ false |
| 出队 | remove() | poll()→ null |
| 查看队首 | element() | peek()→ null |
这种"双API"设计让你可以根据场景选择:如果队列为空是你预料之内的情况,用poll()返回null更优雅;如果队列应该永远非空,用remove()让异常暴露问题更合适。
publicclassQueueDemo{publicstaticvoidmain(String[]args){Queue<String>queue=newLinkedList<>();queue.offer("A");// 入队queue.offer("B");queue.offer("C");System.out.println(queue.poll());// A 出队并移除System.out.println(queue.peek());// B 查看队首不移除System.out.println(queue);// [B, C]}}三、Map接口详解
Map存储键值对(Key-Value),每个Key最多映射一个Value。
3.1 Map核心方法
publicinterfaceMap<K,V>{Vput(Kkey,Vvalue);// 添加键值对Vget(Objectkey);// 根据Key获取ValueVremove(Objectkey);// 根据Key移除booleancontainsKey(Objectkey);// 是否包含KeybooleancontainsValue(Objectvalue);// 是否包含ValueSet<K>keySet();// 获取所有Key的Set集合Collection<V>values();// 获取所有Value的CollectionSet<Map.Entry<K,V>>entrySet();// 获取所有键值对// ...}3.2 HashMap使用示例
publicclassMapDemo{publicstaticvoidmain(String[]args){Map<String,Integer>map=newHashMap<>();map.put("张三",85);map.put("李四",92);map.put("王五",78);// 遍历方式1:通过keySetfor(Stringkey:map.keySet()){System.out.println(key+" -> "+map.get(key));}// 遍历方式2:通过entrySet(推荐,效率更高)for(Map.Entry<String,Integer>entry:map.entrySet()){System.out.println(entry.getKey()+" -> "+entry.getValue());}// 遍历方式3:forEach(Java 8+)map.forEach((key,value)->System.out.println(key+" -> "+value));}}四、迭代器详解
Iterator是遍历集合的统一方式,所有Collection的子类都可以通过iterator()获取迭代器。
4.1 迭代器的三个核心方法
publicclassIteratorDemo{publicstaticvoidmain(String[]args){List<String>list=newArrayList<>();list.add("Java");list.add("Python");list.add("C++");Iterator<String>iterator=list.iterator();while(iterator.hasNext()){Stringelement=iterator.next();System.out.println(element);}}}- hasNext():判断是否还有下一个元素
- next():返回当前元素并将指针后移
- remove():移除上次next()返回的元素
4.2 迭代过程中安全删除元素
遍历集合时,如果直接用集合的remove()方法删除元素,会抛出ConcurrentModificationException。这是因为集合内部有一个modCount计数器,每次结构性修改都会自增,而迭代器在创建时会记录当时的modCount值,每次next()时检查是否一致。如果直接用集合的remove()(会修改modCount),迭代器的检查就会失败——这是一种**fail-fast(快速失败)**机制,用于尽早暴露并发修改问题。
正确做法是使用迭代器的remove()方法,它会同步更新自己的expectedModCount。JDK 8还提供了更简洁的removeIf()方法,内部也是基于迭代器实现。
publicclassSafeRemoveDemo{publicstaticvoidmain(String[]args){List<String>list=newArrayList<>();list.add("Java");list.add("Python");list.add("C++");// 错误做法:会抛出ConcurrentModificationException// for (String s : list) {// if ("Python".equals(s)) {// list.remove(s); // 危险!// }// }// 正确做法:使用迭代器的remove()Iterator<String>it=list.iterator();while(it.hasNext()){Strings=it.next();if("Python".equals(s)){it.remove();// 安全删除}}System.out.println(list);// [Java, C++]}}4.3 增强for循环的本质
增强for循环(foreach)实际上是迭代器的语法糖,编译后等价于使用Iterator遍历:
// 源码写法for(Strings:list){System.out.println(s);}// 编译后等价于for(Iterator<String>it=list.iterator();it.hasNext();){Strings=it.next();System.out.println(s);}五、迭代器模式的设计思想
迭代器模式的精髓在于将遍历行为从集合本身分离出来。这样做的好处是:
- 解耦:遍历算法与集合的实现分离
- 统一接口:无论底层是数组还是链表,遍历方式都一样
- 封装内部结构:调用者无需知道集合的内部实现
设计模式实践
// 使用ListIterator实现双向遍历(仅List实现支持)publicclassListIteratorDemo{publicstaticvoidmain(String[]args){List<String>list=newArrayList<>();list.add("一");list.add("二");list.add("三");ListIterator<String>listIterator=list.listIterator();// 正向遍历while(listIterator.hasNext()){System.out.print(listIterator.next()+" ");// 一 二 三}System.out.println();// 反向遍历while(listIterator.hasPrevious()){System.out.print(listIterator.previous()+" ");// 三 二 一}}}六、集合的选择策略
在实际开发中,选择合适的集合类型非常重要,这直接影响程序的性能和可读性。以下是一些选择建议:
| 需求场景 | 推荐集合 |
|---|---|
| 需要快速随机访问 | ArrayList |
| 频繁插入删除 | LinkedList |
| 需要去重 | HashSet |
| 需要排序 | TreeSet / TreeMap |
| 需要键值对 | HashMap |
| 线程安全场景 | ConcurrentHashMap / CopyOnWriteArrayList |
| 按插入顺序遍历 | LinkedHashMap / LinkedHashSet |
总结
本文介绍了Java集合框架的整体架构,涵盖了Collection和Map两大接口体系,以及迭代器的使用方式。集合框架是Java中最常用的工具库,可以说任何Java项目都离不开它。以下是本文的核心收获:
- Collection体系:List(有序可重复,适合按索引操作)、Set(无序不可重复,适合去重)、Queue(FIFO队列,适合任务调度)三大子接口各有专攻
- Map体系:键值对存储,HashMap是最常用的实现,TreeMap适合排序场景,LinkedHashMap适合按插入顺序遍历
- Iterator迭代器:统一的遍历接口,将遍历逻辑与底层数据结构解耦。增强for循环本质是迭代器的语法糖
- fail-fast机制:
ConcurrentModificationException是集合的"安全阀",防止在遍历过程中被意外修改导致数据不一致
掌握这些基础知识后,在后续文章中我们将深入探讨ArrayList和LinkedList的底层原理、HashMap的哈希表实现、以及多线程环境下的并发集合等高级话题。集合框架的真正功力体现在选型能力上——同样是存储100万条数据,选ArrayList还是LinkedList?选HashMap还是TreeMap?这取决于你对底层数据结构的理解深度。
Java集合框架的设计充分体现了接口与实现分离、抽象层次分明的设计思想。理解这套框架,对于一个Java开发者来说不仅是面试的必备知识,更是写出高质量代码的基础。
✅ 亮点总结
- Collection与Map两大体系划分:Collection存储单列数据(List/Set/Queue),Map存储键值对(HashMap/TreeMap),用一张全景图理清所有集合类的归属
- Iterator迭代器模式的优雅设计:将遍历行为与底层数据结构解耦,无论
ArrayList数组还是LinkedList链表,hasNext()/next()接口完全统一 - ListIterator的双向遍历能力:相比普通Iterator只能"前进",ListIterator支持"后退"(
hasPrevious()/previous()),适合需要双向操作的场景 - 集合选择速查表:一张表格将"需随机访问→ArrayList"、“需去重→HashSet”、"需排序→TreeMap"等常见场景一一对应,减少选型犹豫
- 接口与实现分离的设计思想:
List<String> list = new ArrayList<>()——声明用接口,实现选具体类,这是面向接口编程的经典实践
适用场景
- 全局搜索项目中所有使用
List的地方,检查是否选择了正确的实现类(是否滥用LinkedList或漏用HashSet去重) - 处理从数据库或API返回的批量数据时,根据后续操作(遍历/随机访问/去重/排序)选择合适的集合类型
- 重构代码时,将
for (int i = 0; i < list.size(); i++)统一替换为增强for循环或迭代器,提升代码可读性
扩展方向
- ArrayList vs LinkedList深度对比:理解两者底层数据结构和时间复杂度差异,做出最优选型,推荐阅读 12_ArrayList与LinkedList深度对比
- HashMap底层原理:数组+链表+红黑树的哈希表实现,JDK 1.7到1.8的演进故事,推荐阅读 13_HashMap底层原理详解
- 并发集合:
ConcurrentHashMap的分段锁机制、CopyOnWriteArrayList的写时复制策略,理解多线程环境下的集合安全方案
下一篇:12_ArrayList与LinkedList深度对比
