Java 集合框架(Java Collections Framework)详细介绍

Java 集合框架(Java Collections Framework)详细介绍

Java 集合框架(JCF)是 Java 核心 API 的重要组成部分,旨在提供一套统一、高效的接口和类,用于存储、操作和管理多个对象(称为“元素”)。它解决了数组(固定大小、类型单一)的局限性,支持动态扩容、泛型安全、便捷的元素操作(如增删改查、排序、筛选),并为不同场景(如列表、集合、映射)提供了针对性实现。

一、集合框架的核心结构

Java 集合框架的设计遵循接口(定义行为)- 抽象类(封装共性实现)- 具体类(提供特定功能) 的分层结构,整体可分为两大核心体系:Collection 体系(存储单个元素的集合)和 Map 体系(存储键值对(Key-Value)的映射表)。

1. 顶层接口关系图

Java.util
├─ Collection(单个元素集合顶层接口)
│  ├─ List(有序、可重复)
│  │  ├─ ArrayList(动态数组实现)
│  │  ├─ LinkedList(双向链表实现)
│  │  └─ Vector(线程安全的动态数组,已过时)
│  │     └─ Stack(栈结构,继承 Vector,已过时)
│  ├─ Set(无序、不可重复)
│  │  ├─ HashSet(哈希表实现,基于 HashMap)
│  │  ├─ LinkedHashSet(哈希表+链表,保证插入顺序)
│  │  └─ TreeSet(红黑树实现,保证自然排序)
│  └─ Queue(队列,先进先出 FIFO)
│     ├─ LinkedList(实现 Queue 接口,双端队列)
│     ├─ PriorityQueue(优先级队列,基于堆实现)
│     └─ Deque(双端队列,支持首尾操作)
│        └─ ArrayDeque(动态数组实现的双端队列)
└─ Map(键值对映射顶层接口)
   ├─ HashMap(哈希表实现,线程不安全,JDK 1.8 后为数组+链表+红黑树)
   ├─ LinkedHashMap(哈希表+链表,保证插入/访问顺序)
   ├─ TreeMap(红黑树实现,保证 Key 自然排序)
   ├─ Hashtable(哈希表实现,线程安全,已过时)
   └─ ConcurrentHashMap(线程安全的 HashMap,JDK 1.8 后基于 CAS+Synchronized)

二、Collection 体系详解

Collection 是所有单个元素集合的根接口,定义了操作元素的通用方法(如 add()remove()size()iterator() 等),但它本身是抽象行为定义,无法直接实例化,需通过其子接口(ListSetQueue)的具体类使用。

1. List 接口:有序、可重复的集合

List 是最常用的集合类型之一,核心特点是元素有序(按插入顺序保存)、可重复、支持通过索引(下标)访问元素(类似数组的“位置访问”)。

核心方法(扩展自 Collection)
  • void add(int index, E element):在指定索引插入元素
  • E get(int index):获取指定索引的元素
  • E set(int index, E element):替换指定索引的元素
  • E remove(int index):删除指定索引的元素
  • int indexOf(Object o):返回元素首次出现的索引(不存在则为 -1)
主要实现类对比
实现类底层结构线程安全查找效率插入/删除效率(中间)适用场景
ArrayList动态数组(Object[])高(O(1),索引访问)低(O(n),需移动元素)频繁查找、少量插入/删除的场景
LinkedList双向链表低(O(n),需遍历)高(O(1),仅需修改指针)频繁插入/删除、少量查找的场景
Vector动态数组(Object[])是(方法加 synchronized)同 ArrayList,但性能低同 ArrayList,但性能低已过时,推荐用 CopyOnWriteArrayList(线程安全替代)

示例:ArrayList 使用

List<String> list = new ArrayList<>();
list.add("Apple");  // 末尾添加
list.add(1, "Banana");  // 索引1插入
System.out.println(list.get(0));  // 输出 Apple
list.set(0, "Orange");  // 替换索引0元素
list.remove(1);  // 删除索引1元素
System.out.println(list);  // 输出 [Orange]

2. Set 接口:无序、不可重复的集合

Set 的核心特点是元素无序(插入顺序不保证)、不可重复(通过 equals()hashCode() 判断唯一性),不支持索引访问,仅能通过迭代器或增强 for 循环遍历。

核心约束
  • 插入重复元素时,add() 方法返回 false,且元素不会被重复存储;
  • 元素的“唯一性”依赖两个方法:hashCode()(计算哈希值,用于快速定位)和 equals()(哈希值相同时,判断内容是否相等)。若需自定义对象存入 Set,必须重写这两个方法
主要实现类对比
实现类底层结构线程安全元素顺序查找效率适用场景
HashSet哈希表(基于 HashMap)无序(哈希顺序)高(O(1))无需保证顺序、仅需去重的场景
LinkedHashSet哈希表 + 双向链表保证插入顺序略低于 HashSet(链表维护顺序)需去重且保证插入顺序的场景
TreeSet红黑树(自平衡二叉树)保证自然排序(或自定义排序)O(log n)需去重且按顺序(如升序)存储的场景

示例:TreeSet 自定义排序

// 自定义 Person 类(需实现 Comparable 接口,或在 TreeSet 构造时传入 Comparator)
class Person implements Comparable<Person> {
    private String name;
    private int age;

    @Override
    public int compareTo(Person o) {
        return this.age - o.age;  // 按年龄升序排序
    }

    // 省略构造器、getter、toString()
}

// 使用 TreeSet
Set<Person> set = new TreeSet<>();
set.add(new Person("Alice", 25));
set.add(new Person("Bob", 20));
System.out.println(set);  // 输出 [Person(name=Bob, age=20), Person(name=Alice, age=25)]

3. Queue 接口:先进先出(FIFO)的队列

Queue 模拟现实中的“队列”(如排队买票),核心特点是先进先出(FIFO),仅允许在队尾插入(offer())、队首删除(poll())和访问(peek())。它扩展了 Collection,并提供了针对队列的专用方法。

核心方法(区分“抛出异常”和“返回特殊值”两种风格)
操作抛出异常(容量不足时)返回特殊值(容量不足时)
队尾插入add(E e)offer(E e)(返回 false)
队首删除remove()poll()(返回 null)
队首访问element()peek()(返回 null)
主要实现类
  • LinkedList:同时实现 ListQueue 接口,可作为双端队列(Deque)使用,支持首尾插入/删除。
  • PriorityQueue:优先级队列,不遵循 FIFO,而是按元素优先级(自然排序或自定义排序)提取队首元素(优先级最高的元素),底层基于“堆”(完全二叉树)实现。
  • ArrayDeque:基于动态数组的双端队列(Deque),效率高于 LinkedList,适合作为栈(push()/pop())或队列使用。

示例:PriorityQueue 优先级队列

// 优先级队列:按整数大小升序,队首始终是最小元素
Queue<Integer> pq = new PriorityQueue<>();
pq.offer(5);
pq.offer(2);
pq.offer(8);
System.out.println(pq.poll());  // 输出 2(最小元素)
System.out.println(pq.poll());  // 输出 5

三、Map 体系详解

Map 是存储键值对(Key-Value) 的集合,核心特点是:

  • Key 唯一(不可重复,类似 Set),通过 equals()hashCode() 判断唯一性;
  • Value 可重复,一个 Key 仅对应一个 Value(若重复插入相同 Key,新 Value 会覆盖旧 Value);
  • 访问方式:通过 Key 查找 Value(get(Key k)),而非索引。

1. Map 接口核心方法

  • V put(K key, V value):插入键值对(Key 存在则覆盖 Value,返回旧 Value)
  • V get(Object key):通过 Key 获取 Value(Key 不存在则返回 null)
  • V remove(Object key):通过 Key 删除键值对,返回对应的 Value
  • Set<K> keySet():返回所有 Key 的 Set 集合(用于遍历 Key)
  • Collection<V> values():返回所有 Value 的 Collection 集合(用于遍历 Value)
  • Set<Map.Entry<K, V>> entrySet():返回所有键值对(Entry)的 Set 集合(高效遍历键值对)

2. 主要实现类对比

实现类底层结构线程安全Key 顺序查找效率适用场景
HashMap数组 + 链表 + 红黑树(JDK 1.8+)无序(哈希顺序)O(1)普通场景,无需线程安全和顺序
LinkedHashMap哈希表 + 双向链表保证插入/访问顺序O(1)需按插入/访问顺序遍历键值对(如缓存 LRU 策略)
TreeMap红黑树保证 Key 自然排序/自定义排序O(log n)需按 Key 顺序遍历的场景(如排序的配置表)
Hashtable哈希表是(方法加 synchronized)无序O(1),但性能低已过时,推荐用 ConcurrentHashMap
ConcurrentHashMap数组 + 链表 + 红黑树(JDK 1.8+,CAS+Synchronized)是(分段锁/节点锁,高效)无序接近 HashMap多线程并发场景(如分布式缓存)

示例:HashMap 遍历键值对

Map<String, Integer> map = new HashMap<>();
map.put("Apple", 5);
map.put("Banana", 3);
map.put("Orange", 4);

// 方式1:遍历 Key,再获取 Value(效率较低)
for (String key : map.keySet()) {
    System.out.println(key + ": " + map.get(key));
}

// 方式2:直接遍历 Entry(高效,推荐)
for (Map.Entry<String, Integer> entry : map.entrySet()) {
    System.out.println(entry.getKey() + ": " + entry.getValue());
}

// 方式3:Lambda 表达式(JDK 8+)
map.forEach((key, value) -> System.out.println(key + ": " + value));

四、集合框架的工具类:Collections

java.util.Collections 是一个静态工具类,提供了大量静态方法,用于操作集合(如排序、查找、同步化、创建不可变集合等),无需实例化即可使用。

常用方法

  1. 排序相关

    • void sort(List<T> list):对 List 按自然排序(元素需实现 Comparable);
    • void sort(List<T> list, Comparator<? super T> c):按自定义 Comparator 排序。
  2. 查找相关

    • int binarySearch(List<? extends Comparable<?>> list, Object key):二分查找(需先排序);
    • T max(Collection<? extends T> coll):获取集合中最大元素。
  3. 同步化相关(将非线程安全集合转为线程安全)

    • static <T> List<T> synchronizedList(List<T> list):返回线程安全的 List;
    • static <K,V> Map<K,V> synchronizedMap(Map<K,V> m):返回线程安全的 Map。
  4. 不可变集合相关(创建不可修改的集合,防止外部修改)

    • static <T> List<T> unmodifiableList(List<? extends T> list)
    • static <K,V> Map<K,V> unmodifiableMap(Map<? extends K,? extends V> m)

示例:Collections 排序

List<Integer> list = new ArrayList<>(Arrays.asList(3, 1, 4, 2, 5));
Collections.sort(list);  // 自然排序:[1, 2, 3, 4, 5]
// 自定义降序排序
Collections.sort(list, (a, b) -> b - a);  // 结果:[5, 4, 3, 2, 1]

五、集合框架的关键设计理念

  1. 泛型(Generics):从 JDK 5 引入,确保集合元素类型安全,避免运行时 ClassCastException。例如 List<String> 明确只能存储 String 类型,编译期即可检查类型错误。
  2. 迭代器(Iterator):所有 Collection 的实现类都实现了 Iterable 接口,可通过 iterator() 获取迭代器,用于遍历集合元素。迭代器支持“快速失败”(Fail-Fast)机制:若遍历过程中集合被修改(如 add/remove),会立即抛出 ConcurrentModificationException,避免数据不一致。
  3. 接口解耦:通过接口定义行为,具体类实现细节,用户可根据需求替换实现类(如将 ArrayList 改为 LinkedList,只需修改实例化代码,调用逻辑不变)。

六、常见问题与最佳实践

  1. ArrayList vs LinkedList 如何选择?

    • 频繁查找(get())选 ArrayList(O(1) 效率);
    • 频繁在中间插入/删除(add(int index)/remove(int index))选 LinkedList(O(1) 效率);
    • 若需线程安全,优先用 CopyOnWriteArrayList(而非 Vector)。
  2. HashMap vs Hashtable 区别?

    • 线程安全:HashMap 不安全,Hashtable 安全(但性能低);
    • 键值允许:HashMap 允许 Key/Value 为 null,Hashtable 不允许;
    • 底层优化:HashMap JDK 1.8 后用数组+链表+红黑树,Hashtable 始终用数组+链表。
  3. 自定义对象存入 Set/Map 需注意什么?

    • 必须重写 hashCode()equals() 方法,确保“逻辑相等”的对象有相同的哈希值;
    • 重写规则:若 a.equals(b) 为 true,则 a.hashCode() 必须等于 b.hashCode();反之不强制(但哈希值不同可减少哈希冲突)。
  4. 如何避免 ConcurrentModificationException?

    • 遍历集合时,用迭代器的 remove() 方法(而非集合的 remove());
    • 多线程场景下,用线程安全集合(如 ConcurrentHashMapCopyOnWriteArrayList)。

总结

Java 集合框架为开发者提供了一套全面、高效的“数据容器”解决方案,通过 Collection(单个元素)和 Map(键值对)两大体系覆盖了绝大多数场景需求。掌握不同集合的底层结构、核心特点和适用场景,是编写高效 Java 代码的基础。实际开发中,需根据“是否有序、是否重复、是否线程安全、操作效率需求”选择合适的集合实现类,并结合 Collections 工具类简化操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值