news 2025/12/25 23:13:45

Java集合-List讲解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java集合-List讲解

目录

  • 一、集合框架层次结构
  • 二、Collection集合
    • 1.List集合
      • 1.CopyOnWriteArrayList
      • 2、ArrayList
      • 3、LinkedList
      • 4、Vector

Java 集合框架(Collections Framework)是 Java 中用于存储和操作数据组的重要架构。它提供了一组接口、实现类和算法。

一、集合框架层次结构

Collection (接口) ├── List (接口 - 有序,可重复) │ ├── ArrayList (实现类) │ ├── LinkedList (实现类) │ ├── Vector (线程安全,已过时) │ └── Stack (继承Vector) │ ├── Set (接口 - 无序,不可重复) │ ├── HashSet (实现类) │ │ └── LinkedHashSet (保持插入顺序) │ ├── SortedSet (接口) │ │ └── TreeSet (实现类) │ └── EnumSet (专用于枚举) │ └── Queue (接口 - 队列) ├── Deque (双端队列接口) │ ├── ArrayDeque (实现类) │ └── LinkedList (也实现了Deque) │ ├── PriorityQueue (优先队列) └── BlockingQueue (阻塞队列接口) ├── ArrayBlockingQueue ├── LinkedBlockingQueue └── PriorityBlockingQueue Map (接口 - 键值对) ├── HashMap (实现类) │ └── LinkedHashMap (保持插入顺序) ├── TreeMap (基于红黑树) ├── Hashtable (线程安全,已过时) ├── WeakHashMap (弱引用) └── ConcurrentHashMap (并发版)

Java集合大致可以分为两大体系,一个是Collection,另一个是Map

  • Collection:主要由ListSetQueue接口组成,List代表有序、重复的集合;其中Set代表无序、不可重复的集合;Queue体系集合,代表一种队列集合实现。
  • Map:则代表具有映射关系的键值对集合。
    java.util.Collection下的接口和继承类关系简易结构图:

    java.util.Map下的接口和继承类关系简易结构图:


其中,Java 集合框架中主要封装的是典型的数据结构和算法,如动态数组、双向链表、队列、栈、Set、Map等。

二、Collection集合

通过集合的关系图我们可以知道Collection是集合的顶层父类,他定义了集合的基本方法如

基本操作方法

方法签名功能描述返回值示例时间复杂度
int size()返回集合中元素的数量元素个数list.size()3O(1)
boolean isEmpty()判断集合是否为空true/falselist.isEmpty()falseO(1)
boolean contains(Object o)判断是否包含指定元素true/falselist.contains("A")trueList: O(n)
Set: O(1)
TreeSet: O(log n)
boolean add(E e)添加元素到集合是否成功list.add("D")trueArrayList: 均摊O(1)
LinkedList: O(1)
TreeSet: O(log n)
boolean remove(Object o)移除指定元素是否成功list.remove("A")trueArrayList: O(n)
LinkedList: O(n)
HashSet: O(1)

批量操作方法

方法签名功能描述返回值示例说明
boolean containsAll(Collection<?> c)是否包含集合c中所有元素true/falselist.containsAll(subList)检查子集关系
boolean addAll(Collection<? extends E> c)添加集合c中所有元素是否改变list.addAll(anotherList)批量添加
boolean removeAll(Collection<?> c)移除集合c中所有元素是否改变list.removeAll(toRemove)差集操作
boolean retainAll(Collection<?> c)仅保留集合c中元素是否改变list.retainAll(common)交集操作
void clear()清空集合所有元素list.clear()集合变为空

转换和迭代方法

方法签名功能描述返回值示例说明
Object[] toArray()转换为Object数组Object数组list.toArray()返回新数组
<T> T[] toArray(T[] a)转换为指定类型数组指定类型数组list.toArray(new String[0])类型安全转换
Iterator<E> iterator()返回迭代器Iterator对象list.iterator()用于遍历集合
default boolean removeIf(Predicate<? super E> filter)条件删除是否改变list.removeIf(s -> s.length() > 3)Java 8+
default Spliterator<E> spliterator()返回分割迭代器Spliterator对象list.spliterator()Java 8+,并行遍历
default Stream<E> stream()返回顺序流Stream对象list.stream()Java 8+,流操作
default Stream<E> parallelStream()返回并行流Stream对象list.parallelStream()Java 8+,并行流操作

集合运算方法

方法数学运算示意图示例
addAll()并集A ∪ BA.addAll(B)
retainAll()交集A ∩ BA.retainAll(B)
removeAll()差集A - BA.removeAll(B)

常见操作示例

操作需求代码示例说明
遍历集合for (E e : collection) { ... }增强for循环
安全遍历并删除iterator.remove()使用迭代器删除
转换为数组String[] arr = coll.toArray(new String[0])推荐写法
批量添加元素coll.addAll(Arrays.asList("A","B","C"))初始化集合
过滤集合coll.removeIf(e -> e.startsWith("A"))Java 8+
集合判空if (!coll.isEmpty()) { ... }优于size() > 0

注意事项表格

方法注意事项推荐做法
contains()依赖equals()hashCode()正确实现这两个方法
remove(Object)只删除第一个匹配项使用removeIf()删除所有
toArray()无参方法返回Object[]使用带参方法指定类型
addAll()可能修改原集合注意并发修改异常
clear()不释放元素引用大集合考虑设为null
iterator()遍历时不能修改集合使用迭代器的remove()
场景建议理由
频繁包含检查使用HashSetO(1)时间复杂度
频繁插入删除使用LinkedList首尾操作O(1)
随机访问使用ArrayListO(1)索引访问
需要排序使用TreeSet自动维护顺序
线程安全使用并发集合ConcurrentHashMap
只读操作使用不可变集合Collections.unmodifiableXXX()

Collection集合中所包含的方法:

publicinterfaceCollection<E>extendsIterable<E>{// 基本操作方法intsize();booleanisEmpty();booleancontains(Objecto);booleanadd(Ee);booleanremove(Objecto);// 批量操作booleancontainsAll(Collection<?>c);booleanaddAll(Collection<?extendsE>c);booleanremoveAll(Collection<?>c);booleanretainAll(Collection<?>c);voidclear();// 数组转换Object[]toArray();<T>T[]toArray(T[]a);// 迭代器Iterator<E>iterator();// Java 8 新增方法defaultbooleanremoveIf(Predicate<?superE>filter){...}defaultSpliterator<E>spliterator(){...}defaultStream<E>stream(){...}defaultStream<E>parallelStream(){...}}

1.List集合

List集合的特点就是存取有序,可以存储重复的元素,可以用下标进行元素的操作
该类适用于多线程读多写少并发场景,它在有写操作的时候会copy一份数据,然后写完再设置成新的数据,同时也进行了重入锁的处理保证了安全。

1.CopyOnWriteArrayList

CopyOnWriteArrayListJava并发包中的线程安全List 实现,采用"写时复制"策略

读操作:

// 直接读取,无需加锁publicEget(intindex){returnget(getArray(),index);// 直接访问当前数组}

写操作:

// 修改操作(add/set/remove)publicbooleanadd(Ee){synchronized(lock){// 写操作加锁Object[]elements=getArray();intlen=elements.length;// 1. 创建新数组(长度+1)Object[]newElements=Arrays.copyOf(elements,len+1);// 2. 在新数组上修改newElements[len]=e;// 3. 替换引用setArray(newElements);returntrue;}}

2、ArrayList

它是一个标准的集合实现类,特点为有序,可重复,存储是连续的,因此查询较快,增删较为慢,使用Object数组进行存储。
ArrayList是 Java 中最常用的动态数组实现,基于数组实现,支持动态扩容
ArrayList底层实现:

publicclassArrayList<E>extendsAbstractList<E>implementsList<E>,RandomAccess,Cloneable,java.io.Serializable{// 默认初始容量privatestaticfinalintDEFAULT_CAPACITY=10;// 存储元素的数组transientObject[]elementData;// non-private to simplify nested class access// 当前元素数量privateintsize;// 空数组实例(用于空列表)privatestaticfinalObject[]EMPTY_ELEMENTDATA={};privatestaticfinalObject[]DEFAULTCAPACITY_EMPTY_ELEMENTDATA={};}

核心特性

特性说明
数据结构基于数组
扩容机制增长因子为 1.5 倍
随机访问O(1) 时间复杂度
插入/删除O(n) 时间复杂度(平均)
线程安全非线程安全
内存连续连续内存分配
允许元素允许 null 值,允许重复元素

构造方法

// 1. 默认构造(延迟初始化)ArrayList<String>list1=newArrayList<>();// 初始容量为0,第一次add时扩容到10// 2. 指定初始容量ArrayList<String>list2=newArrayList<>(100);// 初始容量100// 3. 从其他集合构造List<String>existingList=Arrays.asList("A","B","C");ArrayList<String>list3=newArrayList<>(existingList);

扩容过程

// add() 方法中的扩容逻辑publicbooleanadd(Ee){ensureCapacityInternal(size+1);// 确保容量足够elementData[size++]=e;returntrue;}privatevoidensureCapacityInternal(intminCapacity){// 如果是空数组,使用默认容量10if(elementData==DEFAULTCAPACITY_EMPTY_ELEMENTDATA){minCapacity=Math.max(DEFAULT_CAPACITY,minCapacity);}ensureExplicitCapacity(minCapacity);}privatevoidensureExplicitCapacity(intminCapacity){modCount++;// 修改计数++// 需要扩容if(minCapacity-elementData.length>0)grow(minCapacity);}// 核心扩容方法privatevoidgrow(intminCapacity){intoldCapacity=elementData.length;intnewCapacity=oldCapacity+(oldCapacity>>1);// 增长1.5倍if(newCapacity-minCapacity<0)newCapacity=minCapacity;if(newCapacity-MAX_ARRAY_SIZE>0)newCapacity=hugeCapacity(minCapacity);// 创建新数组并拷贝数据elementData=Arrays.copyOf(elementData,newCapacity);}

常用方法详解

1. 添加元素

ArrayList<String>list=newArrayList<>();// 末尾添加list.add("A");// ["A"]list.add("B");// ["A", "B"]// 指定位置插入list.add(1,"C");// ["A", "C", "B"] O(n)操作// 批量添加list.addAll(Arrays.asList("D","E"));// ["A", "C", "B", "D", "E"]// 指定位置批量添加list.addAll(2,Arrays.asList("X","Y"));// ["A", "C", "X", "Y", "B", "D", "E"]

2. 访问元素

ArrayList<String>list=newArrayList<>(Arrays.asList("A","B","C","D"));// 获取元素(随机访问 O(1))Stringfirst=list.get(0);// "A"Stringlast=list.get(list.size()-1);// "D"// 遍历元素for(inti=0;i<list.size();i++){System.out.println(list.get(i));}// 增强for循环for(Stringitem:list){System.out.println(item);}// Java 8+ forEachlist.forEach(System.out::println);// 迭代器遍历Iterator<String>iterator=list.iterator();while(iterator.hasNext()){System.out.println(iterator.next());}

3. 修改元素

ArrayList<String>list=newArrayList<>(Arrays.asList("A","B","C"));// 设置元素(替换)list.set(1,"BB");// ["A", "BB", "C"]// 批量替换(Java 8+)list.replaceAll(s->s+"!");// ["A!", "BB!", "C!"]// 排序list.sort(String::compareTo);// 自然排序list.sort(Comparator.reverseOrder());// 逆序Collections.sort(list);// 传统方式// 洗牌(随机打乱)Collections.shuffle(list);

4. 删除元素

ArrayList<String>list=newArrayList<>(Arrays.asList("A","B","C","D","E","B"));// 按索引删除(返回被删除元素)Stringremoved=list.remove(2);// 删除 "C",返回 "C"// 按元素删除(删除第一个匹配项)booleansuccess=list.remove("B");// 删除第一个 "B",返回 truelist.remove("X");// 元素不存在,返回 false// 批量删除list.removeAll(Arrays.asList("D","E"));// 删除所有匹配项// 条件删除(Java 8+)list.removeIf(s->s.startsWith("A"));// 删除所有以A开头的元素// 保留指定元素(交集)list.retainAll(Arrays.asList("B","C"));// 只保留 B 和 C// 清空list.clear();// 清空所有元素

5. 查找元素

ArrayList<String>list=newArrayList<>(Arrays.asList("A","B","C","B","D"));// 查找索引intfirstIndex=list.indexOf("B");// 1intlastIndex=list.lastIndexOf("B");// 3intnotFound=list.indexOf("X");// -1// 判断包含booleancontainsB=list.contains("B");// truebooleancontainsAll=list.containsAll(Arrays.asList("A","C"));// true// 查找条件匹配(Java 8+)Optional<String>firstMatch=list.stream().filter(s->s.length()>1).findFirst();booleananyMatch=list.stream().anyMatch(s->s.equals("B"));booleanallMatch=list.stream().allMatch(s->s!=null);

3、LinkedList

LinkedList是 Java 中基于双向链表实现List,同时也实现了 Deque 接口,可以作为队列使用。
与其他的实现类不同,他的底层是采用链接形式存储的,因此增删块,查询较慢如:

节点结构

privatestaticclassNode<E>{Eitem;// 存储的元素Node<E>next;// 后继节点Node<E>prev;// 前驱节点Node(Node<E>prev,Eelement,Node<E>next){this.item=element;this.next=next;this.prev=prev;}}

链表结构

publicclassLinkedList<E>extendsAbstractSequentialList<E>implementsList<E>,Deque<E>,Cloneable,java.io.Serializable{transientintsize=0;// 链表大小transientNode<E>first;// 头节点transientNode<E>last;// 尾节点// 节点关系示意图:// first ←→ node1 ←→ node2 ←→ ... ←→ last// ↑ ↑ ↑ ↑// prev=null prev=first prev=node1 prev=...// next=node1 next=node2 next=node3 next=null}

核心特性

特性说明
数据结构双向链表
内存分配非连续内存
随机访问O(n) 时间复杂度
插入/删除O(1) 时间复杂度(已知节点位置)
头尾操作O(1) 时间复杂度
线程安全非线程安全
允许元素允许 null 值,允许重复元素
额外空间每个元素需要存储前后指针

构造方法

// 1. 默认构造(空链表)LinkedList<String>list1=newLinkedList<>();// 2. 从其他集合构造List<String>existingList=Arrays.asList("A","B","C");LinkedList<String>list2=newLinkedList<>(existingList);// 创建后结构:// first → Node("A") ↔ Node("B") ↔ Node("C") ← last// size = 3

1. 添加元素

LinkedList<String>list=newLinkedList<>();// 添加到末尾(List接口)list.add("A");// [A]list.add("B");// [A, B]// 指定位置插入list.add(1,"C");// [A, C, B]// 添加到末尾(等价于add)list.addLast("D");// [A, C, B, D]// 添加到开头list.addFirst("Z");// [Z, A, C, B, D]// 批量添加list.addAll(Arrays.asList("E","F"));// [Z, A, C, B, D, E, F]

2. 访问元素

LinkedList<String>list=newLinkedList<>(Arrays.asList("A","B","C","D","E"));// 获取头尾元素Stringfirst=list.getFirst();// "A"Stringlast=list.getLast();// "E"// 按索引获取(需要遍历)Stringthird=list.get(2);// "C" - 从头开始遍历// 遍历方式for(inti=0;i<list.size();i++){// ❌ 低效:每次get都是O(n)System.out.println(list.get(i));}// ✅ 推荐:迭代器遍历for(Stringitem:list){// 使用迭代器,O(n)总体System.out.println(item);}// ✅ 推荐:列表迭代器(可双向遍历)ListIterator<String>iterator=list.listIterator();while(iterator.hasNext()){System.out.println(iterator.next());}// 反向遍历while(iterator.hasPrevious()){System.out.println(iterator.previous());}

3. 查找元素

LinkedList<String>list=newLinkedList<>(Arrays.asList("A","B","C","B","D"));// 查找索引(从头开始遍历)intfirstIndex=list.indexOf("B");// 1intlastIndex=list.lastIndexOf("B");// 3// 判断包含booleanhasA=list.contains("A");// true// 查找条件匹配(Java 8+)Optional<String>result=list.stream().filter(s->s.startsWith("C")).findFirst();

4. 删除元素

LinkedList<String>list=newLinkedList<>(Arrays.asList("A","B","C","D","E"));// 删除头节点StringremovedFirst=list.removeFirst();// "A"StringpolledFirst=list.pollFirst();// "B"(队列风格)// 删除尾节点StringremovedLast=list.removeLast();// "E"StringpolledLast=list.pollLast();// "D"// 按索引删除(需要遍历到该位置)Stringremoved=list.remove(0);// "C"// 按元素删除(删除第一个匹配项)booleansuccess=list.remove("B");// false("B"已不存在)// 清空list.clear();// first = last = null, size = 0

4、Vector

该类于JDK1.1就出现了,特点为:线程安全但是效率较慢因为他的方法大多采用synchronized进行修饰,也是采用Object数组进行存储
底层数据结构

publicclassVector<E>extendsAbstractList<E>implementsList<E>,RandomAccess,Cloneable,java.io.Serializable{// 存储元素的数组protectedObject[]elementData;// 元素数量protectedintelementCount;// 容量增长系数(扩容时使用)protectedintcapacityIncrement;// 默认初始容量privatestaticfinalintDEFAULT_CAPACITY=10;}

核心特性

特性VectorArrayList说明
线程安全✅ 是(synchronized)❌ 否Vector 的主要特点
数据结构动态数组动态数组底层都是数组
扩容机制可指定增长量,默认2倍固定1.5倍Vector 更灵活
性能较慢(锁开销)较快Vector 有同步开销
迭代器快速失败快速失败都支持 fail-fast
遗留类✅ 是(JDK 1.0)❌ 否(JDK 1.2)Vector 已过时

构造方法

// 1. 默认构造(容量10,满时容量翻倍)Vector<String>vec1=newVector<>();// 2. 指定初始容量Vector<String>vec2=newVector<>(100);// 3. 指定初始容量和容量增长量Vector<String>vec3=newVector<>(100,20);// 初始容量100,每次扩容增加20// 4. 从集合构造List<String>list=Arrays.asList("A","B","C");Vector<String>vec4=newVector<>(list);

扩容逻辑

// Vector 的扩容方法privatevoidgrow(intminCapacity){intoldCapacity=elementData.length;// 关键:如果有 capacityIncrement,按增量增长;否则翻倍intnewCapacity=oldCapacity+((capacityIncrement>0)?capacityIncrement:oldCapacity);if(newCapacity-minCapacity<0)newCapacity=minCapacity;if(newCapacity-MAX_ARRAY_SIZE>0)newCapacity=hugeCapacity(minCapacity);elementData=Arrays.copyOf(elementData,newCapacity);}

扩容示例

// 示例1:默认扩容(翻倍)Vector<Integer>vec1=newVector<>(5);// 初始容量:5vec1.add(1);vec1.add(2);vec1.add(3);vec1.add(4);vec1.add(5);vec1.add(6);// 触发扩容:5 → 10(翻倍)// 示例2:指定增量扩容Vector<Integer>vec2=newVector<>(5,3);// 初始容量:5,增量:3vec2.add(1);vec2.add(2);vec2.add(3);vec2.add(4);vec2.add(5);vec2.add(6);// 触发扩容:5 → 8(5+3)vec2.add(7);vec2.add(8);vec2.add(9);// 触发扩容:8 → 11(8+3)

同步机制

// Vector 的所有公共方法都加了 synchronizedpublicsynchronizedbooleanadd(Ee){modCount++;ensureCapacityHelper(elementCount+1);elementData[elementCount++]=e;returntrue;}publicsynchronizedEget(intindex){if(index>=elementCount)thrownewArrayIndexOutOfBoundsException(index);returnelementData(index);}publicsynchronizedEremove(intindex){modCount++;if(index>=elementCount)thrownewArrayIndexOutOfBoundsException(index);EoldValue=elementData(index);intnumMoved=elementCount-index-1;if(numMoved>0)System.arraycopy(elementData,index+1,elementData,index,numMoved);elementData[--elementCount]=null;// 帮助GCreturnoldValue;}

复合操作的线程安全问题

// 即使单个方法是线程安全的,复合操作也可能有问题Vector<String>vector=newVector<>();// ❌ 线程不安全:check-then-act 模式if(!vector.isEmpty()){// 线程A检查Stringitem=vector.get(0);// 线程B可能在这里remove(0)// 可能抛出 IndexOutOfBoundsException}// ✅ 解决方案:对整个复合操作加锁synchronized(vector){if(!vector.isEmpty()){Stringitem=vector.get(0);// 安全操作}}// ❌ 另一个问题:迭代中的修改for(inti=0;i<vector.size();i++){Stringitem=vector.get(i);// size()和get()之间可能有其他线程修改process(item);}// ✅ 解决方案:迭代时加锁synchronized(vector){for(inti=0;i<vector.size();i++){Stringitem=vector.get(i);process(item);}}

1. 容量管理方法

Vector<String>vec=newVector<>(10);// 获取/设置容量intcapacity=vec.capacity();// 当前容量:10vec.ensureCapacity(100);// 确保容量至少100vec.trimToSize();// 修剪容量到当前大小// 设置大小(可能截断或填充null)vec.setSize(15);// 如果原来小于15,填充nullvec.setSize(5);// 如果原来大于5,截断后面元素// 获取底层数组Object[]array=vec.toArray();

2. 元素操作特有方法

Vector<String>vec=newVector<>(Arrays.asList("A","B","C","D"));// 添加元素(尾部)vec.addElement("E");// 同add()vec.insertElementAt("X",2);// 在索引2处插入// 设置元素vec.setElementAt("BB",1);// 设置索引1为"BB"// 删除元素vec.removeElement("B");// 删除第一个"B"vec.removeElementAt(0);// 删除索引0元素vec.removeAllElements();// 清空所有元素// 查找元素intindex=vec.indexOf("C");// 查找索引intlastIndex=vec.lastIndexOf("D");// 从后往前查找booleancontains=vec.contains("A");// 是否包含// 获取首尾元素Stringfirst=vec.firstElement();// 第一个元素Stringlast=vec.lastElement();// 最后一个元素

3. 枚举器(Enumeration)

Vector<String>vec=newVector<>(Arrays.asList("A","B","C"));// 获取枚举器(旧版迭代器)Enumeration<String>enumeration=vec.elements();// 遍历while(enumeration.hasMoreElements()){Stringelement=enumeration.nextElement();System.out.println(element);}// 与Iterator对比Iterator<String>iterator=vec.iterator();while(iterator.hasNext()){Stringelement=iterator.next();System.out.println(element);iterator.remove();// Enumeration没有remove方法}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/19 5:32:15

部署Qwen3-VL-30B显存需求全解析

Qwen3-VL-30B 显存需求全解析&#xff1a;从参数到生产落地的完整指南 &#x1f680; 你有没有试过满怀期待地把 Qwen3-VL-30B 加载进本地环境&#xff0c;结果刚一启动就弹出 OOM&#xff08;Out of Memory&#xff09;&#xff1f; 看着“激活参数仅 30B”的宣传语&#xff0…

作者头像 李华
网站建设 2025/12/16 14:10:21

无需API也能对话PDF:Anything-LLM开箱即用的文档助手体验

无需API也能对话PDF&#xff1a;Anything-LLM开箱即用的文档助手体验 在办公室里&#xff0c;一位法务人员正面对一份长达80页的合同草案&#xff0c;眉头紧锁。他不想逐字阅读&#xff0c;只关心“有哪些违约责任条款”“保密期限是多久”。过去&#xff0c;这需要几个小时的人…

作者头像 李华
网站建设 2025/12/16 14:05:17

使用LLaMA-Factory快速部署Qwen3-4B模型

使用LLaMA-Factory快速部署Qwen3-4B模型 在大模型应用迅速普及的今天&#xff0c;越来越多开发者希望在本地环境中快速体验或定制自己的AI助手。然而&#xff0c;从零搭建推理环境、处理依赖冲突、应对显存瓶颈等问题&#xff0c;常常让人望而却步。幸运的是&#xff0c;像 LLa…

作者头像 李华
网站建设 2025/12/16 14:04:23

PaddleDetection模型训练日志分析:导出为html报告便于分享

PaddleDetection模型训练日志分析&#xff1a;导出为HTML报告便于分享 在实际AI项目开发中&#xff0c;一个常被忽视但至关重要的环节是——如何让别人快速理解你的模型到底“训得怎么样”。 我们经常遇到这样的场景&#xff1a;训练跑完了&#xff0c;终端输出了一堆数字&…

作者头像 李华