Java集合框架解析:从基础到底层源码

发布于:2025-05-20 ⋅ 阅读:(21) ⋅ 点赞:(0)

Java集合框架解析:从基础到底层源码


一、集合体系

1.1 两大核心接口深度解析

Collection 单列集合
  • List 系列

    • ArrayList:动态数组实现,初始容量10,扩容策略为 原容量的1.5倍
      // JDK17 扩容源码片段
      int newCapacity = oldCapacity + (oldCapacity >> 1);
      
    • LinkedList:双向链表实现,首尾操作时间复杂度O(1)
      // 节点结构源码
      private static class Node<E> {
          E item;
          Node<E> next;
          Node<E> prev;
      }
      
    • Vector:线程安全版ArrayList(方法级synchronized锁)
  • Set 系列

    • HashSet:基于HashMap实现(值存储在Key)
    • TreeSet:红黑树实现有序存储,时间复杂度O(logn)
Map 双列集合(深度扩展)
实现类 数据结构 线程安全方案
HashMap 数组+链表/红黑树(JDK8+) ConcurrentHashMap分段锁
LinkedHashMap 链表维护插入/访问顺序 Collections.synchronizedMap
TreeMap 红黑树 无内置方案

HashMap扩容机制

  1. 默认初始容量16,负载因子0.75
  2. 扩容阈值 = 容量 * 负载因子
  3. 链表长度≥8且数组长度≥64时转红黑树

二、Collection核心机制详解

2.1 迭代器遍历的陷阱与突破

List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));

// 错误示例:触发ConcurrentModificationException
Iterator<String> it = list.iterator();
while(it.hasNext()) {
    String s = it.next();
    if(s.equals("B")) {
        list.remove(s); // 错误!使用集合的remove方法
    }
}

// 正确写法:使用迭代器的remove
Iterator<String> it = list.iterator();
while(it.hasNext()) {
    String s = it.next();
    if(s.equals("B")) {
        it.remove(); // ✅ 安全删除
    }
}

源码级原理

  • modCount机制:集合修改次数计数器
  • 迭代器创建时记录expectedModCount
  • 每次操作前校验modCount == expectedModCount

2.2 遍历方式性能对比

遍历方式 时间复杂度 适用场景
普通for循环 O(n) 需要索引操作的场景
迭代器 O(n) 遍历中需要删除元素
增强for O(n) 简单遍历(语法糖)
forEach+Lambda O(n) 函数式编程风格

三、List集合深度扩展

3.1 ListIterator 的威力

List<String> list = new ArrayList<>();
list.add("A");
list.add("B");

ListIterator<String> lit = list.listIterator();
while(lit.hasNext()) {
    String s = lit.next();
    if(s.equals("B")) {
        lit.add("C"); // ✅ 安全添加元素
        lit.set("D"); // ✅ 修改当前元素
    }
}
// 结果:[A, D, C]

3.2 时间复杂度对比表

操作 ArrayList LinkedList
get(int index) O(1) O(n)
add(E element) O(1) 均摊 O(1)
add(int index, E) O(n) O(n)
remove(int index) O(n) O(n)

四、并发集合与Java8新特性

4.1 线程安全方案对比

实现方式 锁粒度 性能 适用场景
Vector 方法级锁 遗留系统兼容
Collections.synchronizedList 对象锁 中等 低并发场景
CopyOnWriteArrayList 写时复制 读快写慢 读多写少场景

4.2 Stream API实战

List<Employee> employees = ...;

// 统计研发部平均工资
double avgSalary = employees.stream()
        .filter(e -> "研发部".equals(e.getDept()))
        .mapToDouble(Employee::getSalary)
        .average()
        .orElse(0);

// 分组统计部门人数
Map<String, Long> deptCount = employees.stream()
        .collect(Collectors.groupingBy(
            Employee::getDept, 
            Collectors.counting()
        ));

五、高频面试题深度剖析

5.1 HashMap为什么线程不安全?

  1. 数据覆盖问题:多线程put时可能覆盖已有键值对
  2. 扩容死循环:JDK7头插法导致链表成环(JDK8改用尾插法)
  3. 可见性问题:未使用volatile修饰size等字段

5.2 ArrayList与LinkedList的选择依据

  • 查询为主:选ArrayList(CPU缓存友好)
  • 频繁增删:首尾操作选LinkedList,中间操作两者都差
  • 内存敏感:ArrayList更节约空间(无节点指针开销)

六、终极总结:集合框架选用指南

  1. 单线程环境
    • 快速查询:ArrayList/HashMap
    • 频繁增删:LinkedList
    • 需要排序:TreeSet/TreeMap
  2. 高并发场景
    • 读多写少:CopyOnWriteArrayList
    • 写多读少:ConcurrentHashMap
    • 严格一致性:Collections.synchronized系列
  3. 函数式编程
    • 使用Stream API进行链式处理
    • 优先选择不可变集合(Guava/Java9+)

彩蛋知识点
Java9新增工厂方法创建不可变集合:

List<String> list = List.of("A", "B", "C");
Set<Integer> set = Set.of(1, 2, 3);
Map<String, Integer> map = Map.of("A", 1, "B", 2);

通过全面理解集合框架的底层实现与设计哲学,我们可以编写出更高效、更健壮的Java应用程序。建议结合IDE的源码调试功能(如IDEA的View->Tool Windows->Structure),深入体会各集合类的实现细节。


网站公告

今日签到

点亮在社区的每一天
去签到