JAVA数据结构 DAY3-List接口

本系列可作为JAVA学习系列的笔记,文中提到的一些练习的代码,小编会将代码复制下来,大家复制下来就可以练习了,方便大家学习。

点赞关注不迷路!您的点赞、关注和收藏是对小编最大的支持和鼓励!

系列文章目录

JAVA初阶---------已更完

JAVA数据结构 DAY1-集合和时空复杂度

JAVA数据结构 DAY2-包装类和泛型

JAVA数据结构 DAY3-List接口

JAVA数据结构 DAY4-ArrayList


目录

目录

系列文章目录

目录

前言

[一、什么是 List?------ 从接口继承到数据结构本质](#一、什么是 List?—— 从接口继承到数据结构本质)

[1. List 的接口继承关系](#1. List 的接口继承关系)

[2. List 的本质:线性表](#2. List 的本质:线性表)

[二、List 常见接口详解 ------ 核心方法与使用场景](#二、List 常见接口详解 —— 核心方法与使用场景)

[1. List 接口完整方法清单](#1. List 接口完整方法清单)

[2. 核心方法重点解析(含使用场景)](#2. 核心方法重点解析(含使用场景))

(1)增删操作:指定位置的精准控制

(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))。示例:

    java 复制代码
    List<String> list = new ArrayList<>();
    list.add("Java"); // 尾插"Java"
    list.add("Python"); // 尾插"Python"
    // 此时list为["Java", "Python"]
  • add(int index, E element):在指定下标插入元素,插入后原下标及后续元素均向后移位。注意:下标不能超出 [0, size ()] 范围 ,否则会抛出IndexOutOfBoundsException。示例:

    java 复制代码
    list.add(1, "C++"); // 在下标1处插入"C++"
    // 此时list为["Java", "C++", "Python"]
  • remove(int index):删除指定下标的元素,返回被删除的元素,后续元素向前移位。同样需要注意下标合法性([0, size ()-1])。示例:

    java 复制代码
    String removed = list.remove(1); // 删除下标1的"C++"
    System.out.println(removed); // 输出:C++
    // 此时list为["Java", "Python"]
  • remove(Object o):删除第一个遇到的指定元素,若元素不存在则返回 false。注意:该方法依赖元素的 equals () 方法判断是否匹配,因此自定义对象需重写 equals () 方法。示例:

    java 复制代码
    boolean isRemoved = list.remove("Python"); // 删除第一个"Python"
    System.out.println(isRemoved); // 输出:true
    // 此时list为["Java"]
(2)查询与修改:基于下标的快速操作
  • get(int index):获取指定下标的元素,是 List 最核心的查询方法,时间复杂度取决于实现类(ArrayList 为 O (1),LinkedList 为 O (n))。示例:

    java 复制代码
    String element = list.get(0); // 获取下标0的元素
    System.out.println(element); // 输出:Java
  • set(int index, E element):修改指定下标的元素,返回原元素。该方法不会改变 List 的长度,仅替换元素值。示例:

    java 复制代码
    String 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。示例:

    java 复制代码
    List<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。示例:

    java 复制代码
    List<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 接收一个参数,返回同类型结果)。示例:将所有数字翻倍

    java 复制代码
    numList.replaceAll(n -> n * 2);
    System.out.println(numList); // 输出:[4, 12, 4, 16]
  • sort(Comparator<? super E>):按指定的 Comparator 排序,若传入 null 则按元素的自然顺序(需实现 Comparable 接口)排序。示例:按数字降序排序

    java 复制代码
    numList.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数据结构,仅作为一份简单的笔记使用,大家根据注释理解,您的点赞关注收藏就是对小编最大的鼓励!

相关推荐
一方_self2 小时前
了解和使用python的click命令行cli工具
开发语言·python
小芳矶2 小时前
Dify本地docker部署踩坑记录
python·docker·容器
南宫码农2 小时前
我的电视 - Android原生电视直播软件 完整使用教程
android·开发语言·windows·电视盒子
2301_822366352 小时前
使用Scikit-learn构建你的第一个机器学习模型
jvm·数据库·python
CoderCodingNo2 小时前
【GESP】C++四级/五级练习题 luogu-P1223 排队接水
开发语言·c++·算法
像少年啦飞驰点、3 小时前
零基础入门 Spring Boot:从“Hello World”到可上线微服务的完整学习指南
java·spring boot·微服务·编程入门·后端开发
小郎君。3 小时前
【无标题】
python
sycmancia3 小时前
C++进阶01——示例
开发语言·c++
CoderCodingNo3 小时前
【GESP】C++五级/四级练习题 luogu-P1413 坚果保龄球
开发语言·c++·算法