本系列可作为JAVA学习系列的笔记,文中提到的一些练习的代码,小编会将代码复制下来,大家复制下来就可以练习了,方便大家学习。
点赞关注不迷路!您的点赞、关注和收藏是对小编最大的支持和鼓励!
系列文章目录
目录
目录
[一、什么是 List?------ 从接口继承到数据结构本质](#一、什么是 List?—— 从接口继承到数据结构本质)
[1. List 的接口继承关系](#1. List 的接口继承关系)
[2. List 的本质:线性表](#2. List 的本质:线性表)
[二、List 常见接口详解 ------ 核心方法与使用场景](#二、List 常见接口详解 —— 核心方法与使用场景)
[1. List 接口完整方法清单](#1. List 接口完整方法清单)
[2. 核心方法重点解析(含使用场景)](#2. 核心方法重点解析(含使用场景))
[(3)查找元素位置:indexOf 与 lastIndexOf](#(3)查找元素位置:indexOf 与 lastIndexOf)
[(4)截取子 List:subList (int fromIndex, int toIndex)](#(4)截取子 List:subList (int fromIndex, int toIndex))
[(5)替换与排序:replaceAll 与 sort](#(5)替换与排序:replaceAll 与 sort)
[(6)List 专属迭代器:ListIterator](#(6)List 专属迭代器:ListIterator)
[三、List 的使用注意事项 ------ 接口不能实例化,需依赖实现类](#三、List 的使用注意事项 —— 接口不能实例化,需依赖实现类)
[1. 关键前提:List 是接口,不能直接实例化](#1. 关键前提:List 是接口,不能直接实例化)
[2. 实例化方式(面向接口编程)](#2. 实例化方式(面向接口编程))
[3. 常见使用场景选择](#3. 常见使用场景选择)
[4. 其他注意事项](#4. 其他注意事项)
前言
小编作为新晋码农一枚,会定期整理一些写的比较好的代码,作为自己的学习笔记,会试着做一下批注和补充,如转载或者参考他人文献会标明出处,非商用,如有侵权会删改!欢迎大家斧正和讨论!
在 Java 编程中,集合框架是不可或缺的核心部分,而 List 作为其中最常用的接口之一,承担着存储有序、可重复元素的重要职责。无论是日常开发中的数据存储,还是复杂业务场景下的元素操作,List 都发挥着关键作用。本文将从 "什么是 List""List 常见接口""List 的使用" 三个核心维度,结合底层原理与实际应用,全面拆解 List 接口的相关知识,帮助大家彻底掌握这一基础且重要的集合类型。
一、什么是 List?------ 从接口继承到数据结构本质
要理解 List,首先需要明确其在 Java 集合框架中的定位,以及其底层对应的数据结构特征。
1. List 的接口继承关系
在 Java 集合框架中,List 是一个接口 ,其继承体系如下:Iterable <- Collection <- List这意味着 List 不仅继承了 Collection 接口的所有规范,还拥有 Iterable 接口赋予的 "可遍历" 能力。
-
Iterable 接口:作为集合框架的顶层接口之一,Iterable 的核心作用是标记实现类 "支持逐个元素遍历"。它定义了 3 个关键方法:
iterator():返回一个迭代器(Iterator)对象,用于遍历集合元素;forEach(Consumer<? super T>):基于函数式编程的遍历方式,可通过 Lambda 表达式简化遍历逻辑;spliterator():返回一个可分割的迭代器(Spliterator),支持并行遍历,提升大数据量下的遍历效率。
-
Collection 接口:作为 List 的直接父接口,Collection 规范了所有容器类的核心通用方法,这些方法在 List 中均有实现(或重写),具体包括:
方法 功能描述 size()返回集合中元素的个数(返回值为 int) contains(Object o)判断集合中是否包含指定元素(返回值为 boolean) iterator()返回迭代器对象,用于遍历元素 toArray()将集合转换为 Object 类型的数组 toArray(T[] a)将集合转换为指定类型的数组(泛型支持) add(E e)向集合中添加元素(返回值为 boolean,表示添加是否成功) remove(Object o)删除集合中遇到的第一个指定元素(返回值为 boolean) containsAll(Collection<?>)判断集合是否包含另一个集合的所有元素 addAll(Collection<? extends E>)将另一个集合的所有元素添加到当前集合尾部 removeAll(Collection<?>)移除当前集合中与另一个集合共有的所有元素 removeIf(Predicate<? super E>)根据指定条件(Predicate 接口)移除元素 retainAll(Collection<?>)保留当前集合中与另一个集合共有的元素(交集操作) clear()清空集合中的所有元素 equals(Object o)判断当前集合与指定对象是否相等 hashCode()返回集合的哈希值 spliterator()返回可分割迭代器,支持并行遍历 stream()返回集合的顺序流(Stream),支持流式编程 parallelStream()返回集合的并行流,支持多线程流式处理 isEmpty()判断集合是否为空(返回值为 boolean)
2. List 的本质:线性表
从数据结构的角度来看,List 的本质是线性表------ 即由 n 个具有相同类型元素组成的有限序列。线性表的核心特征的是:
- 元素之间具有明确的 "先后顺序",每个元素都有唯一的前驱(除第一个元素)和后继(除最后一个元素);
- 支持在任意位置进行增删改查操作,以及完整的遍历功能。
这也是 List 与 Set(无序、不可重复)最核心的区别:List 保证元素的 "有序性"(插入顺序与存储顺序一致)和 "可重复性"(允许存储多个相同的元素)。
二、List 常见接口详解 ------ 核心方法与使用场景
List 作为 Collection 的子接口,不仅继承了所有父接口的方法,还根据线性表的特性,扩展了一系列针对 "下标操作" 的专属方法。这些方法是 List 最核心的功能,也是日常开发中使用频率最高的部分。
1. List 接口完整方法清单
List 接口的方法可分为 "继承自 Collection 的方法" 和 "List 专属扩展方法" 两类,完整清单如下:
| 方法分类 | 方法签名 | 功能描述 |
|---|---|---|
| 继承方法 | size() |
返回元素个数 |
contains(Object o) |
判断是否包含指定元素 | |
iterator() |
返回普通迭代器 | |
toArray() |
转换为 Object 数组 | |
toArray(T[] a) |
转换为指定类型数组 | |
add(E e) |
尾插元素 e | |
remove(Object o) |
删除第一个遇到的元素 o | |
containsAll(Collection<?>) |
判断是否包含另一个集合的所有元素 | |
addAll(Collection<? extends E>) |
尾插另一个集合的所有元素 | |
removeAll(Collection<?>) |
移除与另一个集合的共有元素 | |
retainAll(Collection<?>) |
保留与另一个集合的共有元素 | |
clear() |
清空所有元素 | |
equals(Object o) |
判断集合是否相等 | |
hashCode() |
返回哈希值 | |
spliterator() |
返回可分割迭代器 | |
isEmpty() |
判断集合是否为空 | |
stream() / parallelStream() |
返回顺序流 / 并行流 | |
removeIf(Predicate<? super E>) |
按条件移除元素 | |
forEach(Consumer<? super T>) |
函数式遍历 | |
| 专属扩展方法 | addAll(int index, Collection<? extends E>) |
在指定下标 index 处插入另一个集合的所有元素 |
replaceAll(UnaryOperator<E>) |
按指定规则(UnaryOperator)替换所有元素 | |
sort(Comparator<? super E>) |
按指定比较器(Comparator)排序 | |
get(int index) |
获取下标 index 处的元素 | |
set(int index, E element) |
将下标 index 处的元素替换为 element | |
add(int index, E element) |
在下标 index 处插入元素 element | |
remove(int index) |
删除下标 index 处的元素(返回被删除的元素) | |
indexOf(Object o) |
返回第一个元素 o 的下标(不存在返回 - 1) | |
lastIndexOf(Object o) |
返回最后一个元素 o 的下标(不存在返回 - 1) | |
listIterator() |
返回 List 专属迭代器(支持双向遍历、添加 / 修改元素) | |
listIterator(int index) |
从指定下标 index 开始的 List 专属迭代器 | |
subList(int fromIndex, int toIndex) |
截取子 List(范围:[fromIndex, toIndex),左闭右开) |
2. 核心方法重点解析(含使用场景)
在上述方法中,以下几个是 List 最常用的核心方法,需要重点掌握其用法和注意事项:
(1)增删操作:指定位置的精准控制
-
add(E e):尾插元素,直接在 List 的末尾添加新元素,时间复杂度取决于实现类(ArrayList 为 O (1),LinkedList 为 O (1))。示例:javaList<String> list = new ArrayList<>(); list.add("Java"); // 尾插"Java" list.add("Python"); // 尾插"Python" // 此时list为["Java", "Python"] -
add(int index, E element):在指定下标插入元素,插入后原下标及后续元素均向后移位。注意:下标不能超出 [0, size ()] 范围 ,否则会抛出IndexOutOfBoundsException。示例:javalist.add(1, "C++"); // 在下标1处插入"C++" // 此时list为["Java", "C++", "Python"] -
remove(int index):删除指定下标的元素,返回被删除的元素,后续元素向前移位。同样需要注意下标合法性([0, size ()-1])。示例:javaString removed = list.remove(1); // 删除下标1的"C++" System.out.println(removed); // 输出:C++ // 此时list为["Java", "Python"] -
remove(Object o):删除第一个遇到的指定元素,若元素不存在则返回 false。注意:该方法依赖元素的 equals () 方法判断是否匹配,因此自定义对象需重写 equals () 方法。示例:javaboolean isRemoved = list.remove("Python"); // 删除第一个"Python" System.out.println(isRemoved); // 输出:true // 此时list为["Java"]
(2)查询与修改:基于下标的快速操作
-
get(int index):获取指定下标的元素,是 List 最核心的查询方法,时间复杂度取决于实现类(ArrayList 为 O (1),LinkedList 为 O (n))。示例:javaString element = list.get(0); // 获取下标0的元素 System.out.println(element); // 输出:Java -
set(int index, E element):修改指定下标的元素,返回原元素。该方法不会改变 List 的长度,仅替换元素值。示例:javaString old = list.set(0, "JavaScript"); // 将下标0的元素改为"JavaScript" System.out.println(old); // 输出:Java // 此时list为["JavaScript"]
(3)查找元素位置:indexOf 与 lastIndexOf
-
indexOf(Object o):从 List 头部开始查找,返回第一个匹配元素的下标,未找到则返回 - 1。 -
lastIndexOf(Object o):从 List 尾部开始查找,返回最后一个匹配元素的下标,未找到则返回 - 1。示例:javaList<Integer> numList = new ArrayList<>(); numList.add(2); numList.add(5); numList.add(2); numList.add(8); int first = numList.indexOf(2); // 查找第一个2的下标 int last = numList.lastIndexOf(2); // 查找最后一个2的下标 System.out.println(first); // 输出:0 System.out.println(last); // 输出:2
(4)截取子 List:subList (int fromIndex, int toIndex)
该方法用于截取 List 的部分元素,返回一个新的 List(注意:返回的子 List 是原 List 的视图,修改子 List 会影响原 List,反之亦然)。范围是左闭右开区间 [fromIndex, toIndex),即包含 fromIndex,不包含 toIndex。
-
合法范围:0 ≤ fromIndex ≤ toIndex ≤ 原 List.size (),否则抛出
IndexOutOfBoundsException。示例:javaList<Integer> sub = numList.subList(1, 3); // 截取下标1到3的元素([5, 2]) sub.set(0, 6); // 修改子List的第一个元素为6 System.out.println(numList); // 原List变为[2, 6, 2, 8]
(5)替换与排序:replaceAll 与 sort
-
replaceAll(UnaryOperator<E>):通过 UnaryOperator 函数式接口,对 List 中的所有元素进行替换(UnaryOperator 接收一个参数,返回同类型结果)。示例:将所有数字翻倍javanumList.replaceAll(n -> n * 2); System.out.println(numList); // 输出:[4, 12, 4, 16] -
sort(Comparator<? super E>):按指定的 Comparator 排序,若传入 null 则按元素的自然顺序(需实现 Comparable 接口)排序。示例:按数字降序排序javanumList.sort((a, b) -> b - a); System.out.println(numList); // 输出:[16, 12, 4, 4]
(6)List 专属迭代器:ListIterator
ListIterator 是 Iterator 的子接口,专为 List 设计,支持以下额外功能:
- 双向遍历:
hasPrevious()(判断是否有前一个元素)、previous()(获取前一个元素); - 插入元素:
add(E e)(在当前迭代位置插入元素); - 修改元素:
set(E e)(修改当前迭代到的元素); - 获取下标:
nextIndex()(获取下一个元素的下标)、previousIndex()(获取前一个元素的下标)。
示例:使用 ListIterator 双向遍历并修改元素
java
ListIterator<Integer> iterator = numList.listIterator();
// 正向遍历
while (iterator.hasNext()) {
int num = iterator.next();
if (num == 4) {
iterator.set(5); // 将4改为5
}
}
// 反向遍历
while (iterator.hasPrevious()) {
System.out.print(iterator.previous() + " "); // 输出:5 4 12 16
}
三、List 的使用注意事项 ------ 接口不能实例化,需依赖实现类
1. 关键前提:List 是接口,不能直接实例化
List 作为接口,仅定义了方法规范,没有具体的实现逻辑,因此不能直接通过 new List () 实例化。若要使用 List,必须选择其实现类,Java 集合框架中最常用的实现类有两个:
ArrayList:基于动态数组实现,查询效率高(O (1)),增删效率低(尤其是中间位置,O (n));LinkedList:基于双向链表实现,增删效率高(O (1)),查询效率低(O (n))。
2. 实例化方式(面向接口编程)
推荐使用 "接口引用指向实现类对象" 的方式实例化,便于后续切换实现类(符合开闭原则):
java
// 实例化ArrayList
List<String> arrayList = new ArrayList<>();
// 实例化LinkedList
List<String> linkedList = new LinkedList<>();
3. 常见使用场景选择
- 若场景以 "查询、修改" 为主(如读取配置列表、展示数据),优先选择
ArrayList; - 若场景以 "增删" 为主(如队列、栈操作),优先选择
LinkedList; - 若需要线程安全的 List,可使用
Collections.synchronizedList(List<T> list)包装,或直接使用CopyOnWriteArrayList(并发场景推荐)。
4. 其他注意事项
- 下标越界问题:List 的下标范围是 [0, size ()-1],增删查改时需避免下标超出该范围,否则抛出
IndexOutOfBoundsException; - 元素相等判断:
contains()、indexOf()、remove(Object o)等方法依赖元素的equals()方法,自定义对象需重写equals()和hashCode()方法(保证一致性); - 空指针问题:若 List 为 null,调用任何方法都会抛出
NullPointerException,建议初始化时直接创建实例(如List<String> list = new ArrayList<>()),而非赋值为 null; - 子 List 的视图特性:
subList()返回的子 List 与原 List 共享底层数据,修改任一对象都会影响另一方,若需独立的子 List,可新建一个集合(如new ArrayList<>(subList))。
四、总结
List 作为 Java 集合框架中最核心的接口之一,其本质是线性表,具备 "有序、可重复" 的特征,同时提供了丰富的增删改查方法,尤其是基于下标的精准操作,满足了大多数场景的数据存储需求。
本文从接口继承关系、核心方法解析、使用注意事项三个层面,全面覆盖了 List 的相关知识:
- 继承体系:List 继承自 Collection,间接继承自 Iterable,拥有通用方法和遍历能力;
- 核心方法:重点掌握下标操作(get/set/add/remove)、位置查找(indexOf/lastIndexOf)、子 List 截取、迭代器使用等;
- 实例化:依赖 ArrayList、LinkedList 等实现类,根据场景选择合适的实现类。

掌握 List 的使用,是 Java 编程的基础,也是后续学习集合框架其他组件(如 Set、Map)的前提。在实际开发中,需结合业务场景选择合适的实现类,并注意规避下标越界、空指针、equals 方法未重写等常见问题,才能充分发挥 List 的优势。
总结
以上就是今天要讲的内容,本文简单记录了java数据结构,仅作为一份简单的笔记使用,大家根据注释理解,您的点赞关注收藏就是对小编最大的鼓励!