2025/7/13——java学习总结

集合进阶学习总结:从接口到源码的体系化突破

一、核心知识深耕:集合体系与底层逻辑拆解

(一)Collection 接口:单列集合的行为规范

作为 ListSet 的顶层接口,定义增删查遍历的通用契约:

  • 核心方法add(E)remove(Object)iterator()size()contains(Object)
  • 设计哲学 :通过接口解耦 "行为定义" 与 "实现细节"(如 ArrayList 用数组、LinkedList 用链表),支持面向抽象编程

(二)迭代器(Iterator):遍历的统一范式

  • 核心能力hasNext() 判空、next() 取值、remove() 删除(需紧跟 next() 调用);
  • 底层机制
    • 快速失败(fail-fast) :通过 modCount(集合修改次数)与 expectedModCount(迭代器记录的修改次数)对比,检测并发修改,抛出 ConcurrentModificationException
    • 实现差异ArrayListItr 直接操作数组索引,LinkedListListItr 基于链表节点双向遍历。

(三)增强 for + Lambda:遍历的语法糖进化

  • 增强 for :本质是 Iterator 的语法糖(自动创建迭代器),简化代码但不支持索引操作
  • Lambda + forEach :结合 Collection.forEach(Consumer),利用函数式接口实现极简遍历 (如 list.forEach(System.out::println)),底层仍依赖迭代器。

(四)List 接口:有序集合的精细化操作

  • 特有方法 :索引操作(get(int)add(int, E)remove(int))、双向迭代器 ListIterator(支持 previous() 反向遍历、中间修改);

  • 遍历对比

    方式 效率(ArrayList) 效率(LinkedList) 支持操作
    普通 for ✔️ O (1)(随机访问) ❌ O (n)(遍历) 索引控制
    增强 for ✔️ 语法糖 ❌ 遍历耗时 简单遍历
    Iterator ✔️ 通用 ✔️ 链表友好 删除操作
    ListIterator ✔️ 双向 ✔️ 双向 中间插入 / 修改
    Lambda forEach ✔️ 极简 ❌ 遍历耗时 无状态操作

(五)数据结构对比:数组 vs 链表 vs 栈 vs 队列

结构 底层实现 核心特性 典型操作效率
数组 连续内存 随机访问快,增删中间慢 get() O(1),add(中间) O(n)
链表 离散节点(prev/next) 增删头尾快,随机访问慢 addFirst() O(1),get() O(n)
数组 / 链表 后进先出(LIFO) push()/pop() O(1)
队列 链表(如 LinkedList 先进先出(FIFO) offer()/poll() O(1)

(六)ArrayList 源码:动态数组的扩容艺术

  • 初始化 :JDK 8+ 无参构造器初始为空数组 ,首次 add 时扩容为 10
  • 扩容策略 :默认扩容 1.5 倍oldCapacity + (oldCapacity >> 1)),通过 Arrays.copyOf(native 方法)高效拷贝数组;
  • 性能陷阱 :中间增删触发元素移动(O (n)),批量添加建议提前 ensureCapacity 减少扩容次数。

(七)LinkedList 与迭代器:双向链表的设计

  • 结构 :内部类 Node<E> 存储元素及前后指针,头尾节点 first/last
  • 迭代器ListItr 维护当前节点、前一节点,支持双向遍历和中间修改;
  • 性能短板 :遍历效率低于 ArrayList(链表节点分散,缓存不友好),适合头尾高频增删场景。

(八)泛型:类型安全的屏障

  • 核心概念 :泛型类(List<E>)、泛型方法(<T> T func(T t))、通配符(? extends E 只读,? super E 可写);
  • 底层真相类型擦除 (编译期替换为 Object 或边界类型),运行时无泛型信息,需通过反射或 @SuppressWarnings 处理类型转换。

二、实践突破:集合的场景化应用

(一)ArrayList 扩容验证(反射揭秘容量变化)

java

复制代码
public class ArrayListCapacity {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < 20; i++) {
            list.add(i);
            System.out.println("size: " + list.size() + ", capacity: " + getCapacity(list));
        }
    }
    private static int getCapacity(ArrayList<?> list) {
        try {
            Field field = ArrayList.class.getDeclaredField("elementData");
            field.setAccessible(true);
            return ((Object[]) field.get(list)).length;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
}
// 输出:首次 add 后容量 10,满后扩容 15(10→15→22...),验证 1.5 倍扩容逻辑

(二)LinkedList 性能对比(头尾 vs 中间操作)

java

复制代码
public class LinkedListPerfTest {
    public static void main(String[] args) {
        LinkedList<Integer> list = new LinkedList<>();
        
        // 头尾操作(O(1),极快)
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            list.addFirst(i); // 或 addLast
        }
        System.out.println("头尾操作耗时:" + (System.currentTimeMillis() - start) + "ms");
        
        // 中间插入(O(n),极慢)
        start = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            list.add(50000, i); // 中间位置插入
        }
        System.out.println("中间插入耗时:" + (System.currentTimeMillis() - start) + "ms");
    }
}
// 结论:头尾操作高效,中间插入因遍历节点耗时剧增

(三)迭代器 fail-fast 演示(并发修改异常)

java

复制代码
public class FailFastDemo {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>(List.of("A", "B", "C"));
        Iterator<String> it = list.iterator();
        while (it.hasNext()) {
            String s = it.next();
            if ("B".equals(s)) {
                // list.remove(s); // 非迭代器删除,触发 ConcurrentModificationException
                it.remove(); // 正确方式:通过迭代器删除,避免异常
            }
        }
        System.out.println(list); // 输出:[A, C]
    }
}

(四)泛型通配符实践(读写边界控制)

java

复制代码
// 泛型类
class Box<T> { private T value; /* ... */ }

public class GenericWildcard {
    public static void main(String[] args) {
        Box<Integer> intBox = new Box<>(10);
        Box<Double> doubleBox = new Box<>(3.14);
        
        printBox(intBox);  // 上限通配符:接受 Number 及其子类(如 Integer)
        addNumber(doubleBox); // 下限通配符:接受 Double 及其父类(如 Number、Object)
    }
    
    // 只读:只能 get,不能 set(除 null)
    public static void printBox(Box<? extends Number> box) {
        System.out.println(box.get()); // 合法:Number 类型
        // box.set(20); // 非法:无法确定具体类型
    }
    
    // 可写:只能 set 子类实例(如 Double)
    public static void addNumber(Box<? super Double> box) {
        box.set(2.718); // 合法:Double 是 ? super Double 的子类型
        // box.set(10); // 非法:Integer 不是 Double 的父类
    }
}

三、底层原理:集合的运行机制解析

(一)Collection 接口的设计思想

  • 依赖倒置 :业务代码依赖 Collection 接口,而非具体实现(如 ArrayList),便于切换存储结构(如 ArrayList → LinkedList);
  • 开闭原则 :新增集合类型(如 CopyOnWriteArrayList)只需实现接口,不影响上层逻辑。

(二)迭代器 fail-fast 的实现

  • ArrayList 内部维护 modCount(每次增删操作自增);
  • 迭代器创建时记录 expectedModCount = modCount
  • 每次 next()/remove() 时校验 expectedModCount == modCount,不等则抛 ConcurrentModificationException快速暴露并发问题

(三)ArrayList 扩容的底层逻辑

  • 内存拷贝Arrays.copyOf 调用 native 方法,直接操作内存块,比 Java 循环拷贝快 3~5 倍;
  • 扩容触发 :当 size == capacity 时触发,空构造器首次 add 会初始化容量为 10;
  • 内存碎片 :频繁扩容可能导致内存浪费,建议通过 ensureCapacity 预分配空间。

(四)LinkedList 的链表模型

  • 节点内存 :每个 Node 占 3 个引用(itemprevnext),内存分散,缓存命中率低(对比 ArrayList 的连续数组);
  • 头尾操作 :直接修改 first/last 指针,时间复杂度 O (1);中间操作需遍历节点,时间复杂度 O (n)。

(五)泛型的类型擦除

  • 编译期处理List<String> 编译后变为 List<Object>,泛型信息仅用于编译期类型检查;
  • 运行时陷阱 :反射获取泛型类型需通过 TypeToken(如 Gson 反序列化),否则会丢失类型信息。

四、总结与展望:从 "会用" 到 "精通" 的进阶

今日突破:

  • 技术维度:掌握集合体系(Collection → List → 实现类)、迭代器机制、数据结构对比、源码分析(ArrayList/LinkedList)、泛型应用;
  • 实践细节:规避 ArrayList 扩容陷阱、LinkedList 中间操作低效、迭代器删除异常、泛型通配符读写限制;
  • 底层认知:接口解耦思想、fail-fast 实现、动态数组扩容算法、链表内存模型、泛型类型擦除。

后续规划:

  1. 技术深化

    • 深入 并发集合CopyOnWriteArrayListConcurrentLinkedQueue),理解线程安全实现;
    • 探索 集合工具类Collections 排序、同步、不可变集合);
    • 拓展 泛型高级应用(TypeToken 规避类型擦除、通配符复杂场景);
    • 剖析 Map 体系(HashMap 哈希表、TreeMap 红黑树),关联集合知识。
  2. 设计模式融合

    • 工厂模式:封装集合创建(如根据场景选择 ArrayList/LinkedList);
    • 装饰器模式:扩展集合功能(同步装饰、只读装饰);
    • 迭代器模式:自定义迭代器(如二叉树中序遍历迭代器)。
  3. 工程化实践

    • 性能优化:根据场景选集合(查询用 ArrayList,头尾增删用 LinkedList);
    • 线程安全:区分同步集合(Vector)与并发集合(CopyOnWriteArrayList)的适用场景;
    • 单元测试:覆盖集合边界条件(空集合、扩容、迭代器异常);
    • 异常处理:完善索引越界、并发修改等异常捕获。
  4. 细节攻坚

    • 优化 ArrayList 扩容:通过 ensureCapacity 减少内存分配次数;
    • 解决 LinkedList 遍历低效:转数组后遍历,提升缓存命中率;
    • 深入泛型类型擦除:反射获取泛型信息,解决 JSON 反序列化类型丢失问题;
    • 理解迭代器弱一致性:分析 CopyOnWriteArrayList 迭代器的 "旧数据" 特性。

持续在 "接口规范 → 实现细节 → 源码分析 → 工程优化" 的闭环中迭代,让集合知识从 "会用" 升级为 "懂设计、知原理、能调优",为高并发队列、内存缓存、复杂数据结构等场景奠定坚实基础 ✨。