Java List 完全指南:从接口特性到四大实现类深度解析

Java List 完全指南:从接口特性到四大实现类深度解析

一、介绍

List 是 Java 集合框架(java.util)中有序、可重复 的集合接口,继承自 Collection 接口,是日常开发中最常用的集合类型之一。其核心特征是:元素按插入顺序排列、允许重复元素、支持通过索引访问元素

特性:

  1. 有序性:元素的存储顺序与插入顺序一致,可通过索引(0 开始)精准访问 / 修改元素。
  2. 可重复性 :允许添加多个相同的元素(equals() 返回 true 的元素)。
  3. 支持 null :允许存储 null 元素(不同实现类对 null 的支持略有差异,如 CopyOnWriteArrayList 也支持,但 Vector 同样支持)。
  4. 索引操作 :提供大量基于索引的方法(如 get(int index)set(int index, E element)),这是与 Set 最核心的区别。

二、List 接口核心方法

List 继承了 Collection 的所有方法,并扩展了索引相关的核心方法:

方法 作用
E get(int index) 获取指定索引的元素
E set(int index, E element) 替换指定索引的元素,返回原元素
void add(int index, E element) 在指定索引插入元素,后续元素后移
E remove(int index) 删除指定索引的元素,返回被删除元素
int indexOf(Object o) 返回元素首次出现的索引,不存在则返回 -1
int lastIndexOf(Object o) 返回元素最后出现的索引,不存在则返回 -1
List<E> subList(int fromIndex, int toIndex) 截取子列表(左闭右开),注意:子列表是原列表的视图,修改会同步
ListIterator<E> listIterator() 返回支持双向遍历的迭代器(可向前 / 向后遍历,还能添加 / 修改元素)

三、List 主要实现类

Java 提供了多个 List 实现类,适配不同的业务场景,核心有以下 4 种:

1. ArrayList(最常用)

  • 底层实现 :基于动态扩容的数组(初始容量 10,扩容时默认扩容 1.5 倍)。

    补充:

    ArrayList 的本质是可变长度的 Object 数组(JDK 8 及以上),所有元素都存储在这个数组中,数组的「固定长度」特性通过「扩容机制」被封装,对外表现为 "动态列表"。

    java 复制代码
    // ArrayList 核心底层数组(JDK 8 源码核心片段)
    public class ArrayList<E> extends AbstractList<E> implements List<E> {
        // 存储元素的底层数组(transient 表示不参与默认序列化)
        transient Object[] elementData;
        // 集合中实际元素的数量(≠ elementData.length)
        private int size;
        
        // 空数组常量(初始无参构造时使用)
        private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    }
    属性 作用
    elementData 核心存储数组,类型为 Object [],存放所有 ArrayList 元素;初始无参构造时,该数组为「空数组」(DEFAULTCAPACITY_EMPTY_ELEMENTDATA),首次添加元素时才初始化容量。
    size 记录集合中实际元素个数(而非数组长度),例如数组长度为 10 但只存了 3 个元素,size=3。
    DEFAULT_CAPACITY 默认初始容量(值为 10),首次添加元素时数组会扩容至 10。
    MAX_ARRAY_SIZE 数组最大容量(Integer.MAX_VALUE - 8),避免数组占用过多内存导致 OOM。
    构造方法:

    1.无参构造:

    java 复制代码
    List<String> list = new ArrayList<>();

    2.指定初始容量构造

    java 复制代码
    List<String> list = new ArrayList<>(20);

    3.基于集合构造

    java 复制代码
    List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
    扩容:

    调用 add()/addAll() 时,若 size + 新增元素数 > elementData.length,触发扩容。

    java 复制代码
    // 1. 计算新容量:默认扩容1.5倍
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    // 2. 若新容量不足(如新增大量元素),直接扩容至「所需最小容量」
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    // 3. 若新容量超过MAX_ARRAY_SIZE,修正为Integer.MAX_VALUE(避免溢出)
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // 4. 拷贝原数组元素到新数组(核心:Arrays.copyOf)
    elementData = Arrays.copyOf(elementData, newCapacity);
    /*
    扩容倍数:默认 1.5 倍(oldCapacity >> 1 等价于 oldCapacity/2);
    扩容开销:扩容需要拷贝数组元素(System.arraycopy),属于 O (n) 操作,因此提前指定初始容量能减少扩容次数,提升性能;
    空列表首次扩容:无参构造的 ArrayList 首次 add 时,直接将数组扩容至 10(而非 1.5 倍,因为初始数组长度为 0)。
    */
  • 核心特点:

    • 随机访问快(数组索引直接访问,时间复杂度 O (1));
    • 插入 / 删除慢(需移动元素,时间复杂度 O (n));
    • 非线程安全 (多线程操作会抛出 ConcurrentModificationException);
    • 支持快速随机遍历,适合读多写少的场景。
  • 使用示例

java 复制代码
List<String> arrayList = new ArrayList<>();
arrayList.add("Java");
arrayList.add("Python");
String first = arrayList.get(0); // 获取第一个元素
arrayList.set(1, "C++"); // 替换第二个元素

2. LinkedList

  • 底层实现 :基于双向链表(每个节点存储前驱、后继和元素)。

    补充:

    LinkedList 的本质是双向循环链表(逻辑上)/ 双向非循环链表(物理实现),每个元素封装为「节点(Node)」,节点间通过前驱 / 后继指针相连,整体无固定长度的数组,而是通过指针动态拼接。

    java 复制代码
    // 私有静态内部类:链表的最小单元
    private static class Node<E> {
        E item; // 节点存储的元素
        Node<E> next; // 指向后继节点的指针(下一个节点)
        Node<E> prev; // 指向前驱节点的指针(上一个节点)
    
        // 节点构造器:初始化前驱、元素、后继
        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

    属性:

    java 复制代码
    public class LinkedList<E> extends AbstractSequentialList<E>
        implements List<E>, Deque<E> {
        transient int size = 0; // 链表中实际元素个数
        transient Node<E> first; // 指向链表头节点的指针
        transient Node<E> last; // 指向链表尾节点的指针
    }
    属性 作用
    first 头节点指针:若链表为空,first = null;否则指向第一个节点(prev = null)。
    last 尾节点指针:若链表为空,last = null;否则指向最后一个节点(next = null)。
    size 记录节点总数,避免遍历计数(O (1) 获取长度)。

    结构示意:

    复制代码
    null ← [prev|item1|next] ↔ [prev|item2|next] ↔ [prev|item3|next] → null
            ↑(first)                          ↑(last)
    • 头节点:prev = nullnext 指向第二个节点;
    • 尾节点:next = nullprev 指向倒数第二个节点;
    • 中间节点:prev 指向前一个,next 指向后一个;
    • 空链表:first = last = nullsize = 0
    构造方法(两种):

    1.无参构造:

    java 复制代码
    List<String> list = new LinkedList<>();

    2.基于集合构造:

    java 复制代码
    List<String> list = new LinkedList<>(Arrays.asList("a", "b", "c"));
  • 核心特点:

    • 随机访问慢(需遍历链表,时间复杂度 O (n));
    • 首尾插入 / 删除快(无需移动元素,时间复杂度 O (1));
    • 非线程安全;
    • 实现了 Deque 接口,可作为队列 / 双端队列使用;
    • 适合写多读少、频繁增删的场景。
  • 使用示例

java 复制代码
List<String> linkedList = new LinkedList<>();
linkedList.addFirst("A"); // 头部添加
linkedList.addLast("B"); // 尾部添加
linkedList.removeFirst(); // 删除头部

3. Vector(古老的线程安全实现)

  • 底层实现 :基于数组,与 ArrayList 类似,但方法加了 synchronized 锁

    补充:

    Vector 的本质是线程安全的动态扩容数组 ,与 ArrayList 一样,所有元素存储在 Object 数组中,核心区别是:Vector 的核心方法通过 synchronized 修饰实现线程安全,扩容倍数和初始化逻辑也不同。

    java 复制代码
    public class Vector<E> extends AbstractList<E> implements List<E> {
        // 存储元素的底层数组(与 ArrayList 的 elementData 一致)
        protected Object[] elementData;
        // 集合中实际元素个数(与 ArrayList 的 size 一致)
        protected int elementCount;
        // 扩容增量(可选:指定扩容时每次增加的容量,默认0)
        protected int capacityIncrement;
    
        // 序列化版本号(ArrayList 也有,仅序列化用)
        private static final long serialVersionUID = -2767605614048989439L;
    }
    属性 作用 与 ArrayList 对比
    elementData 核心存储数组,类型为 Object [] 完全一致(ArrayList 用 transient 修饰,Vector 用 protected 修饰)
    elementCount 实际元素个数(等价于 ArrayList 的 size) 命名不同,功能完全一致
    capacityIncrement 扩容增量:1. 若 > 0,扩容时数组长度 += 该值;2. 若 ≤ 0,扩容时数组长度翻倍(默认 0) ArrayList 无此属性,固定扩容 1.5 倍
    DEFAULT_CAPACITY 默认初始容量(值为 10) 与 ArrayList 一致,但初始化逻辑不同

    构造方法(四种):

    1.无参构造

    java 复制代码
    Vector<String> vector = new Vector<>();

    2.指定初始容量构造

    java 复制代码
    Vector<String> vector = new Vector<>(20);

    3.指定初始容量 + 扩容增量构造

    java 复制代码
    Vector<String> vector = new Vector<>(20, 5);

    4.基于集合构造

    java 复制代码
    Vector<String> vector = new Vector<>(Arrays.asList("a", "b", "c"));
    扩容:

    调用 add()/addAll() 时,若 elementCount + 新增元素数 > elementData.length,触发扩容。

    java 复制代码
    // 1. 计算新容量
    int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);
    // 2. 若新容量不足(如新增大量元素),直接扩容至所需最小容量
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    // 3. 拷贝原数组元素到新数组(与 ArrayList 一致,用 Arrays.copyOf)
    elementData = Arrays.copyOf(elementData, newCapacity);
    /*
    扩容倍数规则:
    若 capacityIncrement > 0:扩容后容量 = 原容量 + capacityIncrement(如初始 20、增量 5,扩容后 25);
    若 capacityIncrement ≤ 0:扩容后容量 = 原容量 × 2(默认翻倍,ArrayList 是 1.5 倍);
    扩容开销:与 ArrayList 一致,扩容需拷贝数组(O (n) 操作),且翻倍扩容比 1.5 倍更易造成内存浪费;
    示例:
    无参构造的 Vector(初始 10,增量 0):首次扩容至 20,第二次至 40,第三次至 80...
    指定增量 5 的 Vector(初始 20):首次扩容至 25,第二次至 30,第三次至 35...
    */
  • 核心特点:

    • 线程安全(但锁粒度大,性能差);
    • 扩容默认 2 倍(ArrayList 1.5 倍);
    • 基本被 CopyOnWriteArrayList 替代,仅兼容旧代码时使用。

4. CopyOnWriteArrayList(并发安全)

  • 底层实现 :基于写时复制数组(修改操作会复制一份新数组,修改后替换原数组)。

    补充:

    CopyOnWriteArrayList 的本质是 "只读原数组 + 写时复制新数组" 的动态数组结构,核心设计思想:

    • 读操作直接访问「不可变的原数组」,无需加锁,性能极高;
    • 写操作(增 / 删 / 改)先复制一份新数组,在新数组上完成修改,再替换原数组,全程加锁保证线程安全;
    • 所有数组操作均基于「不可变数组」,天然避免了并发修改异常(ConcurrentModificationException)。
    java 复制代码
    public class CopyOnWriteArrayList<E> implements List<E>, RandomAccess {
        // 全局锁:仅用于写操作(add/remove/set),读操作无锁
        final transient ReentrantLock lock = new ReentrantLock();
        // 存储元素的底层数组(volatile 修饰,保证多线程可见性)
        private transient volatile Object[] array;
    
        // 获取当前数组(核心内部方法)
        final Object[] getArray() {
            return array;
        }
    
        // 替换数组(仅写操作后调用)
        final void setArray(Object[] a) {
            array = a;
        }
    }
    属性 作用 核心设计考量
    lock 可重入锁(ReentrantLock) 仅锁定写操作,保证同一时间只有一个线程执行 "复制数组 + 修改",避免多线程写冲突;读操作完全无锁。
    array 存储元素的核心数组(volatile 修饰) 1. volatile 保证数组引用的可见性:修改后新数组的引用能立即被其他线程感知;2. 数组本身是 "不可变" 的:读操作期间数组不会被修改,无需担心并发问题。
    构造方法:

    1.无参构造

    java 复制代码
    CopyOnWriteArrayList<String> cowList = new CopyOnWriteArrayList<>();

    2.基于集合构造

    java 复制代码
    CopyOnWriteArrayList<String> cowList = new CopyOnWriteArrayList<>(Arrays.asList("a", "b", "c"));
    写时复制原理:

    1.读操作(无锁 + O (1) 高效)

    读操作(get()/iterator()/contains() 等)全程无锁,直接访问当前 array 数组,无需担心并发修改:

    java 复制代码
    // get(int index):无锁,直接索引访问
    public E get(int index) {
        return elementAt(getArray(), index); // getArray() 返回当前 array,elementAt 等价于 (E) array[index]
    }
    
    // 迭代器:基于当前数组创建"快照迭代器",遍历期间原数组修改不影响迭代结果
    public Iterator<E> iterator() {
        return new COWIterator<>(getArray(), 0); // 传入当前数组的副本,迭代器仅遍历该副本
    }
    • 核心优势:读操作无锁、无阻塞,即使写操作正在执行,读操作仍访问旧数组,不会抛出 ConcurrentModificationException
    • 小缺点:读操作可能读取到 "旧数据"(最终一致性),适合对数据实时性要求不高、读多写少的场景(如配置缓存)。

    2.写操作(加锁 + 复制数组 + O (n) 开销)

    所有写操作(add()/remove()/set())都遵循「加锁 → 复制原数组 → 修改新数组 → 替换原数组 → 解锁」的流程,核心是 "不修改原数组,仅修改副本"。

    写操作中的部分细节介绍:

    1. 锁粒度:仅写操作加锁,读操作不受影响,相比 Vector 的 "方法级 synchronized",并发性能提升极大;
    2. 数组复制开销:写操作需拷贝整个数组(O (n) 时间复杂度),写频率越高,性能越差,因此仅适合 "读多写少" 场景;
    3. 内存占用:写操作期间会同时存在原数组和新数组两份内存,内存开销较大(如原数组 100 万元素,写时需额外占用 100 万元素的内存);
    4. 数据一致性 :写操作的结果需等 setArray() 后才对其他线程可见,读操作可能读取到修改前的旧数据(最终一致性,非强一致性)。

    (1)新增操作(add (E e)):

    java 复制代码
    public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock(); // 1. 加锁,独占写操作
        try {
            Object[] elements = getArray(); // 2. 获取当前原数组
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len + 1); // 3. 复制新数组(长度+1)
            newElements[len] = e; // 4. 在新数组尾部添加元素
            setArray(newElements); // 5. 替换原数组(volatile 保证可见性)
            return true;
        } finally {
            lock.unlock(); // 6. 解锁,释放锁
        }
    }

    (2)删除操作(remove (int index)):

    java 复制代码
    public E remove(int index) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            E oldValue = elementAt(elements, index); // 暂存被删除元素
            int numMoved = len - index - 1;
            Object[] newElements;
            if (numMoved == 0) {
                // 删除最后一个元素:复制长度-1的新数组
                newElements = Arrays.copyOf(elements, len - 1);
            } else {
                // 删除中间元素:分两段拷贝(前半段 + 后半段)
                newElements = new Object[len - 1];
                System.arraycopy(elements, 0, newElements, 0, index);
                System.arraycopy(elements, index + 1, newElements, index, numMoved);
            }
            setArray(newElements); // 替换原数组
            return oldValue;
        } finally {
            lock.unlock();
        }
    }

    (3)修改操作(set (int index, E element)):

    java 复制代码
    public E set(int index, E element) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            E oldValue = elementAt(elements, index);
            if (oldValue != element) { // 元素不同才复制修改
                int len = elements.length;
                Object[] newElements = Arrays.copyOf(elements, len); // 复制等长新数组
                newElements[index] = element; // 修改新数组指定位置
                setArray(newElements);
            } else {
                // 元素相同,无需修改,直接返回(避免无意义的数组复制)
                setArray(elements);
            }
            return oldValue;
        } finally {
            lock.unlock();
        }
    }
  • 核心特点:

    • 线程安全(读操作无锁,写操作加锁但不阻塞读);
    • 读性能极高,写性能较低(复制数组开销大);
    • 迭代器是 "快照",不会抛出 ConcurrentModificationException
    • 适合读多写少的并发场景(如配置缓存、日志收集)。
  • 使用示例

java 复制代码
List<String> cowList = new CopyOnWriteArrayList<>();
cowList.add("a");
cowList.add("b");
// 多线程遍历无需加锁
for (String s : cowList) {
    System.out.println(s);
}

四、List 常见使用场景

场景 推荐实现类
日常开发、读多写少、随机访问 ArrayList
频繁增删(尤其是首尾)、队列 / 栈场景 LinkedList
多线程并发、读多写少 CopyOnWriteArrayList
旧代码兼容、低并发线程安全 Vector

五、注意事项

  1. subList 陷阱:

    subList()返回的是原列表的视图,修改子列表会同步修改原列表,且子列表生命周期依赖原列表(原列表结构修改后,子列表操作会抛异常)。

    java 复制代码
    List<Integer> list = new ArrayList<>(Arrays.asList(1,2,3));
    List<Integer> sub = list.subList(0,2);
    sub.add(4); // 原列表变为 [1,2,4,3]
    list.clear(); // 原列表清空后,sub.get(0) 会抛异常
  2. 迭代器遍历:

    遍历 List 时,若需删除元素,需使用ListIterator的remove()方法,而非for循环(否则抛ConcurrentModificationException)。

    java 复制代码
    List<String> list = new ArrayList<>(Arrays.asList("a","b","c"));
    ListIterator<String> it = list.listIterator();
    while (it.hasNext()) {
        if (it.next().equals("b")) {
            it.remove(); // 安全删除
        }
    }
  3. 空值处理 :List 允许存储 null,但实际开发中应尽量避免(容易导致 NullPointerException,且部分场景如排序会报错)。

  4. 线程安全 :ArrayList/LinkedList 非线程安全,多线程修改时需手动加锁(如 Collections.synchronizedList()),或直接使用 CopyOnWriteArrayList。


六、总结

List 是 Java 中有序可重复的集合,核心实现类各有侧重:

  • ArrayList:性能均衡,适合大多数场景;
  • LinkedList:适合频繁增删的场景;
  • CopyOnWriteArrayList:适合并发读多写少的场景;
  • Vector:尽量避免使用,仅兼容旧代码。

选择时需根据 "访问效率、修改频率、并发场景" 三大维度权衡。

附表:
JDK 版本 List 接口核心变更 ArrayList 关键变更 LinkedList 关键变更 Vector 关键变更 CopyOnWriteArrayList 关键变更
JDK 1.2 1. 正式引入 List 接口,继承 Collection,定义核心索引方法(get/set/add(int, E)/remove(int) 等);2. 同时引入 ArrayListLinkedListVector 实现类;3. Vector 作为早期线程安全实现,方法已加 synchronized 1. 初始版本基于动态数组实现,默认初始容量 10;2. 扩容逻辑为「按需扩容」,早期扩容倍数不固定(后续 JDK 1.4 定型为 1.5 倍);3. 无 trimToSize() 之外的内存优化方法。 1. 基于双向链表实现,实现 List 接口但未实现 Deque;2. 仅提供基础的增删改查方法,无 addFirst/addLast 等队列方法(后续 JDK 1.6 补充)。 1. 初始版本即线程安全(方法加 synchronized);2. 扩容默认翻倍(capacityIncrement 默认为 0);3. 核心属性 elementDataprotected 修饰。 未引入(属于并发包,JDK 1.5 才加入)
JDK 1.3 无接口层面变更,仅优化集合框架的内部迭代器实现,减少 ConcurrentModificationException 触发概率。 优化数组拷贝逻辑,引入 System.arraycopy 替代原生循环拷贝,提升扩容性能。 优化链表节点的内存布局,减少空指针异常风险;新增 indexOf/lastIndexOf 方法的遍历优化。 无核心变更,仅修复少量线程安全漏洞(如扩容时的竞态条件)。 未引入
JDK 1.4 1. 新增 ListIterator 接口,支持双向遍历、添加 / 修改元素;2. List 接口新增 listIterator() 方法;3. 完善 subList() 方法规范,明确子列表为原列表视图。 1. 定型扩容逻辑:默认扩容 1.5 倍(oldCapacity + (oldCapacity >> 1));2. 新增 ensureCapacity(int) 方法,支持手动预扩容;3. 修复 subList 视图修改导致的数组越界问题。 1. 实现 ListIterator 接口,支持双向迭代;2. 优化链表遍历性能,减少节点指针遍历开销。 1. 新增 isEmpty() 方法的优化(直接判断 elementCount == 0);2. 对齐 ArrayListtrimToSize() 方法。 未引入
JDK 1.5 1. 引入泛型(Generic),List 接口支持类型参数(List<E>),解决原始类型的类型安全问题;2. 新增 Collections.synchronizedList(List) 工具方法,为非线程安全 List 提供线程安全包装。 1. 全面支持泛型,替换所有 Object 强转,避免类型转换异常;2. 优化空列表初始化(引入空数组常量,减少内存占用)。 1. 支持泛型,节点 Node 改为泛型类型(Node<E>);2. 新增 offer/peek/poll 等队列方法(初步兼容队列特性)。 1. 支持泛型;2. 性能优化:减少 synchronized 锁的不必要开销。 1. 首次引入(位于 java.util.concurrent 包);2. 基于写时复制(COW)实现,支持基本的增删改查;3. 初始版本已实现 RandomAccess 接口,支持随机访问。
JDK 1.6 1. List 接口新增 toArray(T[] a) 重载方法,支持指定类型数组返回;2. LinkedList 实现 Deque 接口,扩展队列 / 双端队列能力。 1. 优化 addAll 方法的扩容逻辑,减少多次扩容;2. 修复迭代器遍历期间的并发修改异常(fast-fail 机制优化)。 1. 实现 Deque 接口,新增 addFirst/addLast/removeFirst/removeLast 等方法;2. 优化链表首尾操作性能(直接通过 first/last 指针访问,无需遍历)。 1. 新增 copyInto(Object[]) 方法的重载;2. 标记为「低效线程安全实现」,官方推荐优先使用 CopyOnWriteArrayList 1. 优化写操作的锁粒度(使用 ReentrantLock 替代 synchronized);2. 新增 iterator() 快照迭代器,避免并发修改异常。
JDK 1.7 无接口层面核心变更,仅优化集合框架的内存占用。 1. 移除 elementData 中的多余空数组常量,减少内存浪费;2. 优化 trimToSize() 方法,避免不必要的数组拷贝。 优化链表节点的创建逻辑,减少对象创建开销;修复空链表操作时的空指针异常。 无核心变更,仅维护性修复。 1. 优化数组复制逻辑,使用 Arrays.copyOf 替代手动循环;2. 修复写操作时的内存溢出问题(新增 MAX_ARRAY_SIZE 限制)。
JDK 1.8 1. 引入 Stream API,List 可通过 stream()/parallelStream() 实现流式操作;2. 新增 forEach(Consumer) 方法,支持函数式遍历;3. 新增 replaceAll(UnaryOperator)sort(Comparator) 方法。 1. 实现 forEach/replaceAll/sort 方法,适配函数式编程;2. 优化 stream() 遍历性能,减少迭代器创建开销;3. 无参构造时,elementData 初始化为空数组(延迟扩容至首次 add 时的 10)。 1. 适配 Stream API 和函数式方法;2. 优化 sort 方法,先转为数组排序再重建链表(提升排序性能)。 1. 适配函数式方法(forEach/replaceAll);2. 官方文档明确标注「过时推荐使用 CopyOnWriteArrayList」。 1. 适配 Stream API 和函数式遍历;2. 优化读操作的可见性(array 数组保持 volatile 修饰);3. 减少写操作时的无意义数组复制(如 set 方法判断元素是否相同)。
JDK 9 1. 新增 List.of() 静态工厂方法,创建不可变 List(元素不可增删改,不支持 null);2. 新增 List.copyOf() 方法,复制现有集合为不可变 List。 无核心实现变更,仅兼容 List.copyOf() 方法(返回不可变 ArrayList 视图)。 无核心变更,List.copyOf() 对 LinkedList 复制时转为不可变数组实现。 无核心变更,List.copyOf() 不推荐用于 Vector。 1. 兼容 List.copyOf() 方法,返回不可变副本;2. 优化锁的公平性,减少写操作的锁竞争。
JDK 10+ 1. 不可变 List 进一步优化(减少内存占用,提升遍历性能);2. 修复 subList() 视图在并发场景下的异常。 1. 优化内存布局,使用压缩指针减少 elementData 数组的内存开销;2. 修复扩容时的整数溢出问题(hugeCapacity 方法优化)。 优化链表节点的 GC 回收效率,减少内存泄漏风险。 仅维护性修复,无功能增强。 1. 优化写操作的数组复制性能(引入 JVM 层面的数组拷贝优化);2. 修复迭代器快照的一致性问题。
相关推荐
韩立学长5 小时前
【开题答辩实录分享】以《智慧酒店管理——手机预订和住宿管理》为例进行选题答辩实录分享
android·java·后端
何中应5 小时前
【面试题-8】Spring/Spring MVC/Spring Boot/Spring Cloud
java·spring boot·后端·spring·mvc·面试题
坐不住的爱码5 小时前
mybatis-动态sql语句-<foreach>
java·sql·mybatis
while(1){yan}5 小时前
HTTP的数据报格式
java·开发语言·网络·网络协议·http·青少年编程·面试
wuguan_5 小时前
C#之List数组
开发语言·c#·list
ID_180079054735 小时前
淘宝关键词搜索 API 系列 数据返回参考(附解析与实战)
java·服务器·前端
Seven975 小时前
剑指offer-51、构建乘积数组
java
宵时待雨5 小时前
C语言笔记归纳19:动态内存管理
java·开发语言·算法
沉浮yu大海5 小时前
基于SpringBoot3+Java17+Nacos的配置中心和本地配置文件加解密
java·spring cloud·nacos·java17