Java 中的 ArrayList 和 LinkedList

news2024/12/23 4:46:50

一、Java 中的列表

1.1 介绍

列表是一种数据结构,为了方便理解,我们可以认为它是动态的数组。众所周知,数组的大小在定义的时候就固定了,不可改变,那么它就无法存储超过它容量的数据,而列表的容量是无限大的,因为它可以随着其存储内容的大小进行动态的变化(包括容量扩增和缩小),这和 java.util.Vector 很像,但又不完全相同。

Java 中对列表的实现有两种,ArrayList 和 LinkedList。

1.2 继承结构

Java 的整个集合框架继承比较复杂,这里只画出和 ArrayList、LinkedList 相关的部分。

说明:灰色是接口(Interface),黄色是抽象类(AbstractClass),橙色是实现类(Class);虚线是实现(inplements),实线是继承(extends)。

Java 列表继承结构图

由上面可见,ArrayList 和 LinkedList 功能应该是类似的,只不过内部实现方式不同,各有优缺点,各有各的适用场景。它们都位于 java.util 中。

二、ArrayList

2.1 介绍

ArrayList 是 Java 中列表的一种实现,从类名中我们可以看出,它的底层是用数组实现的,因此 ArrayList 本质上就是一个数组队列,提供了添加、删除和修改等基本方法。

2.2 方法

下面给出类 ArrayList 的常用方法。

方法描述
boolean add(E element)将 element 添加到 ArrayList 的末尾,添加成功则返回 true
void add(int index, E element)将 elemnet 插入到索引为 index 的位置
boolean addAll(Collection c)将集合 c 中的所有元素添加到 ArrayList 的末尾,成功则返回 true
boolean addAll(int index, Collection c)将集合 c 中的所有元素插入到索引为 index 的位置,成功则返回 true
void clear()清除 ArrayList 的所有元素
Object clone()返回 ArrayList 的浅拷贝
boolean contains(Object o)判断 ArrayList 是否含有对象 o
boolean containsAll(Collection c)判断 ArrayList 是否含有集合 c 中的全部对象 o
E get(int index)返回索引值为 index 的元素
int indexOf(Object o)返回对象 o 在 ArrayList 中最先出现的索引,不存在则返回 -1
int lastIndexOf(Object o)返回对象 o 在 ArrayList 中最后出现的索引,不存在则返回 -1
boolean retainAll(Collection c)保留 ArrayList 中与集合 c 的交叉元素,成功则返回 true
boolean removeAll(Collection c)移除 ArrayList 中与集合 c 的交叉元素,成功则返回 true
boolean remove(Object o)移除 ArrayList 中最先出现的一个对象 o
E remove(int index)移除索引为 index 的元素并返回该元素
int size()返回 ArrayList 的元素个数
boolean isEmpty()判断 ArrayList 是否为空
List<E> subList(int fromIndex, int toIndex)返回 ArrayList 索引从 fromIndex 开始,toIndex 结尾的部分,不包含索引为 toIndex 的元素
E set(int index, E element)将 ArrayList 索引为 index 的元素替换为 element,并返回被替换的元素
void sort(Comparator c)根据比较接口 c 来对 ArrayList 进行排序
Object[] toArray()返回将 ArrayList 转换后的 Object 类型的数组,元素类型没有改变
T[] toArray(T[] a)返回将 ArrayList 转换后的 T 类型数组
String toString()将 ArrayList 转换成 String 类型
void ensureCapacity(int minCapacity)将 ArrayList 的容量大小设置为 minCapacity
void trimToSize()将 ArrayList 的容量大小设置为当前元素个数
void replaceAll(UnaryOperator<E> operator)将 ArrayList 的每个元素都执行操作 operator,并替换将返回值替换原来的元素
boolean removeIf(Predicate<E> filter)移除 ArrayList 中符合过滤器 filter 的元素,如果成功则返回 true
void forEach(Comsumer<E> action)对 ArrayList 的每个元素都执行操作 action

代码示例:

import java.util.*;
class Test {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<>();
        arrayList.add("ArrayList"); // 增加元素
        arrayList.add(0, "Java"); // 插入元素
        for (String s:arrayList) System.out.println(s); // 打印元素
        arrayList.replaceAll(String::toUpperCase); // 替换为大写
        arrayList.forEach(System.out::println); // 打印元素
        System.out.println(arrayList); // Output: [JAVA, ARRAYLIST]
    }
}

2.3 扩容机制

ArrayList 的底层实现是数组,但数组是定长,而 ArrayList 的动态大小的,因此 ArrayList 需要在容量不够的时候进行扩容。当容量不够的时候,ArrayList 会重新开一个原来 1.5 倍大小的新数组,并将原来的数据都搬到新的数组中去,以此来完成扩容的操作。

但这里有个问题,扩容之后,ArrayList 的数组会有很多空的部分,虽然只是 1.5 倍,看起来不是很多,但在原来的数组就特别大的情况下,这 1.5 倍就显得格外多了,太浪费了,而且可能导致机器内存不足。因此 ArrayList 就设计了一些方法来解决这个问题,比如方法 ensureCapacity,它可以一次性直接将容量设置到指定的大小,防止在某些情况自动扩容导致内存不足,而方法  trimToSize 可以将容量大小立即设置为当前元素的数量,这样数组中就不会有多余的部分了。

2.4 性能分析

因为 ArrayList 是用数组实现的,因此在遍历元素上非常有优势,但由于数组定长,扩容时需要新开辟内存空间,同时还要搬运原来的数据到新的数组中,效率较低,因此 ArrayList 在增减元素这方面就稍微慢了一点。

三、LinkedList

3.1 介绍

LinkedList 的底层是用链表实现的,链表是一种特殊的数据结构,主要分为单向链表和双向链表。除此之外,其余的都和 ArrayList 比较相像。

对于单向链表,每个节点都指向下一个节点的内存地址,而对于双向链表,每个节点都有两个分别指向前一个节点和后一个节点内存地址的值。LinkedList 的底层就是双向链表。

链表的结构

3.2 具体方法

下面具体描述 LinkedList 的常用方法。

方法描述
boolean add(E e)向 LinkedList 的末尾添加元素 e,成功则返回 true
void add(int index, E element)向索引为 index 的位置添加元素 element
boolean addAll(Collection c)将集合 c 中的全部元素添加到 LinkedList 的末尾,成功则返回 true
void addAll(int index, Collection c)将集合 c 中的全部元素添加到 LinkedList 中索引为 index 的位置
void addFirst(E e)将元素 e 添加到 LinkedList 的最前端
void addLast(E e)将元素 e 添加到 LinkedList 的最后端
boolean offer(E e)将元素 e 添加到 LinkedList 的末尾,成功则返回 true
boolean offerFirst(E e)将元素 e 添加到 LinkedList 的最前端,成功则返回 true
boolean offerLast(E e)将元素 e 添加到 LinkedList 的最后端,成功则返回 true
void clear()清空 LinkedList 的全部元素
E removeFirst()移除 LinkedList 中最前端的元素,并返回这个元素
E removeLast()移除 LinkedList 中最后端的元素,并返回这个元素
boolean remove(Object o)移除 LinkedList 中最先出现的对象 o,成功则返回 true
E remove(int index)移除 LinkedList 中索引为 index 的元素
E poll()移除 LinkedList 中最前端的元素,并返回这个元素
E remove()移除 LinkedList 中最前端的元素,并返回这个元素
boolean contains(Object o)判断 LinkedList 是否包含对象 o
E get(int index)返回 LinkedList 中索引为 index 的元素
E getFirst()返回 LinkedList 中最前端的元素
E getLast()返回 LinkedList 中最后端的元素
int indexOf(Object o)返回 LinkedList 中最先出现对象 o 的索引,若没有则返回 -1
int lastIndexOf(Object o)返回 LinkedList 中最后出现对象 o 的索引,若没有则返回 -1
E element()返回 LinkedList 的第一个元素
E peek()返回 LinkedList 的第一个元素
E peekFirst()返回 LinkedList 的头部元素
E peekLast()返回 LinkedList 的尾部元素
E set(int index, E element)将 LinkedList 中索引为 index 的元素替换为元素 element,并返回被替换的元素
Object clone()返回 LinkedList 的浅拷贝
Iterator descendingIterator()返回 LinkedList 的倒序迭代器
int size()返回 LinkedList 的元素个数
ListIterator listIterator()返回 LinkedList 的顺序迭代器
ListIterator listIterator(int index)返回 LinkedList 从索引为 index 的位置开始的顺序迭代器
Object[] toArray()返回将 LinkedList 转换后的 Object 类型的数组,元素类型没有改变
T[] toArray(T[] a)返回将 LinkedList 转换后的 T 类型数组
String toString()将 LinkedList 转换成 String 类型

代码示例:

import java.util.*;
class Test {
    public static void main(String[] args) {
        LinkedList<String> linkedList = new LinkedList<>();
        linkedList.add("LinkedList"); // 增加元素
        linkedList.add(0, "Java"); // 插入元素
        for (String s:linkedList) System.out.println(s); // 打印元素
        linkedList.replaceAll(String::toUpperCase); // 替换为大写
        linkedList.forEach(System.out::println); // 打印元素
        System.out.println(linkedList); // Output: [JAVA, LINKEDLIST]
    }
}

3.3 性能分析

LinkedList 的底层是用链表这种数据结构实现的,而链表每个节点之间是通过内存地址来联系的,因此它不能像数组那样直接访问到某一索引处的元素,只能从头开始遍历,直到找到该元素,所以 LinkedList 在遍历上性能偏低。但正因为它是由链表实现的,不需要像 ArrayList 那样对数组进行 1.5 倍大小的扩容,每次增加元素只需要扩增一个节点就行了,因此 LinkedList 在增减元素上性能较好。

四、二者的联系和区别

4.1 联系

ArrayList 和 LinkedList 都是用来存储数据的线性结构,都属于 Java 中的集合框架,都实现了 List 接口的功能。

4.2 区别

ArrayList 和 LinkedList 各有优缺点,适用场景不一样。

  • ArrayList 的底层数据结构是数组;LinkedList 的底层数据结构是链表;
  • ArrayList 在遍历元素上性能较优,而在增减元素上性能较差;LinkedList 在遍历元素上性能较差,而在增减元素上性能较优;
  • 一般情况下,由于 ArrayList 的 1.5 倍扩容机制,因此 ArrayList 比 LinkedList 更占用内存空间;相同容量情况下,由于 LinkedList 每个节点需要记住前后节点的地址,因此 LinkedList 比 ArrayList 更加占用内存空间;

查找和修改需要较高的遍历性能,而增加和减少需要较高的增减性能。因此,若需要频繁地查找和修改元素,且一般只在末尾增减元素的情况下,应该采用 ArrayList;在需要频繁增减开头和中间部分元素的情况下,应该采用 LinkedList。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/801116.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OSI 7层模型 TCPIP四层模型

7层模型&#xff1a; 各层的用途&#xff1a; 应用层&#xff1a;实现各应用之间信息交换的服务&#xff0c;定义了各个应用传输信息格式&#xff0c;即&#xff0c;定义了传输信息的协议&#xff08;如Web应用的传输信息协议 HTTP、远程登录协议Telnet、安全的网络传输协议SS…

机器人制作开源方案 | 可变式智能正姿椅

作者&#xff1a;吴菁菁 徐乐 张志强 单位&#xff1a;河海大学 指导老师&#xff1a;施敏虎 赵建华 一、作品简介 1. 作品介绍 久坐本身及其导致的各种错误坐姿行为常常会引发一系列健康问题&#xff0c;不利于人体健康。 椅子作为人在久坐状态下与人体接触时间最长的工具则…

【Unity实用插件篇】| A* Pathfinding Project - A*寻路插件 的使用教程

前言【Unity实用插件篇】| A*寻路插件学习使用一、A*算法 简述二、A* Pathfinding Project 介绍2.1 A* Pathfinding Project 功能2.2 相关链接2.3 标准版和Pro版区别2.4 A* Pathfinding Project Free与Navigation的对比三、快速搭建一个自己的场景测试寻路3.1 寻路场景搭建3.2 …

大型系统的任务调度模块实现思路

产品需求&#xff1a;需要一个任务调度模块&#xff0c;用户可以通过页面去新建任务&#xff0c;任务主要就是定时发送邮件&#xff0c;或者每周几去发送邮件&#xff0c;用户可以自定义发送的规则&#xff0c;且用户可以暂停任务、删除任务&#xff0c;也能知道任务的执行情况…

查找-多路查找详解篇

多路查找树 多路查找树&#xff08;Multway Search Tree&#xff09;是一种高级的树形数据结构&#xff0c;它 允许每个节点有多个子节点&#xff08;通常大于等于2&#xff09;。多路查找树的每个节点 可以存储多个关键字和对应的值。分类 2-3树&#xff08;2-3 Tree&#x…

红队打靶,红日系列,红日靶场5

文章目录 靶场详情外网渗透端口扫描漏洞发现与利用获取shell 内网渗透提权内网信息收集 横向移动上线msf路由转发与代理通道Psexec 攻击 靶场详情 此次靶场虚拟机共用两个&#xff0c;一个外网一个内网&#xff0c;用来练习红队相关内容和方向&#xff0c;主要包括常规信息收集…

Eurographics 2023最新综述:图形学中的神经-符号模型

随着 CVPR 2023 Best Paper 的公布&#xff0c;其中一篇名为 VISPROG 的工作引起了广泛关注。这项工作利用自然语言指令解决复杂且组合性的视觉任务&#xff0c;重新将神经-符号方法带回了人们的视野&#xff0c;并证明了计算机视觉社区对这种方法的认可。实际上&#xff0c;VI…

Unity自定义后处理——用偏导数求图片颜色边缘

大家好&#xff0c;我是阿赵。   继续介绍屏幕后处理效果的做法。这次介绍一下用偏导数求图形边缘的技术。 一、原理介绍 先来看例子吧。   这个例子看起来好像是要给模型描边。之前其实也介绍过很多描边的方法&#xff0c;比如沿着法线方向放大模型&#xff0c;或者用Ndo…

数据结构和算法——排序算法的比较和排序综测测验

目录 排序算法的比较 排序综合测验 快又稳定 元素错位 有序排序 排序结果 排序算法的比较 排序方法平均时间复杂度最坏情况下时间复杂度额外空间复杂度稳定性简单选择排序不稳定冒泡排序稳定直接插入排序稳定希尔排序不稳定堆排序不稳定快速排序不稳定归并排序稳定基数排…

SCT2632——65V输出3A非同步整流DCDC转换器

SCT2632是一款3A降压转换器&#xff0c;具有宽输入电压&#xff0c;从4.2V到60V&#xff0c;集成了220mΩ高压侧MOSFET。SCT2632采用峰值电流模式控制&#xff0c;支持脉冲跳过调制&#xff08;PSM&#xff09;&#xff0c;以帮助转换器在轻负载或待机状态下实现高效率条件。SC…

矿用人员定位系统在矿山事故预防中的效果评估

矿业行业的高风险和复杂环境使得采矿安全成为一项重要的挑战。为了保障矿工的安全并减少事故风险&#xff0c;矿用人员定位系统成为了关键技术之一。 在这篇文章中&#xff0c;华安联大便和大家各位朋友一起探讨矿用人员定位系统的重要性、工作原理、作用&#xff0c;并通过真…

Packet Tracer - 配置和验证 NTP

Packet Tracer - 配置和验证 NTP 地址分配表 设备 接口 IP 地址 子网掩码 N1 NIC 209.165.200.225 255.255.255.0 R1 G0/0 209.165.200.226 255.255.255.0 R2 G0/0 209.165.200.227 255.255.255.0 目标 在本练习中&#xff0c;您将在 R1 和 R2 中配置 NTP 以…

苍穹外卖day07——缓存菜品套餐+购物车功能实现

缓存菜品——需求设计与分析 问题说明 用户访问量过大带来的一个直接效果就是响应速度慢&#xff0c;使用体验下降。 实现思路 使用redis缓存菜品数据&#xff0c;减少数据库查询操作。 页面展示上基本就是同一个分类在同一页&#xff0c;所以key-value结构可以使用不同的分…

【SQL应知应会】表分区(二)• Oracle版

欢迎来到爱书不爱输的程序猿的博客, 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 本文收录于SQL应知应会专栏,本专栏主要用于记录对于数据库的一些学习&#xff0c;有基础也有进阶&#xff0c;有MySQL也有Oracle 分区表 • Oracle版 前言一、分区表1.什么是表分区…

富文本编辑器wangEditor初探

1、前言 现有的Quill比较简单&#xff0c;无法满足业务需求&#xff08;例如SEO的图片属性编辑需求&#xff09; Quill已经有比较长的时间没有更新了&#xff0c;虽然很灵活&#xff0c;但是官方demo都没有一个。 业务前期也没有这块的需求&#xff0c;也没有考虑到这块的扩展…

如何提高代码效率——时间复杂度与空间复杂度——【C语言】

当我们面对一个问题时&#xff0c;会有许多种解题思路。我们现在的计算机技术已经达到非常先进的地步&#xff0c;所以当我们用不同的方法对待问题时&#xff0c;时间差异不会很明显&#xff0c;内存差异我们一般在平常小问题时感受不到&#xff0c;所以我们不会去纠结程序的优…

基于ssm+mysql+html道路养护管理系统

基于ssmmysqlhtml道路养护管理系统 一、系统介绍二、功能展示1.道路信息管理2.损害类型信息管理3.损害类型信息管理4.评定等级信息管理5.日常巡查信息管理6.定期检查信息管理 四、获取源码 一、系统介绍 系统主要功能&#xff1a;道路信息管理、损害类型信息管理、评定等级信息…

VSCode SSH远程连接与删除

1.ubuntu设置 安装SSH服务并获取远程访问的IP地址 在Ubuntu系统中&#xff0c;“CtrlAltT”打开终端工具&#xff0c;执行如下命令安装SSH服务。 sudo apt-get install openssh-server如果安装失败则先安装依赖项。 2.VS Code 设置 2.1安装与设置Remote SSH 打开Windows系…

今天,我被二维码卷到了...

# 关注并星标腾讯云开发者# 每周4 | 鹅厂一线程序员&#xff0c;为你“试毒”新技术# 第1期 | 腾讯王锐&#xff1a;测评二维码艺术画生成体验 都说AI绘画来势汹汹&#xff0c;但论创意&#xff0c;还是人类玩得花&#x1f92b;。下面这几张乍一看平平无奇、却在网上疯传的AI生…

rcu链表综合实践

基础知识 rcu-read copy update的缩写。和读写锁起到相同的效果。据说牛逼一点。对于我们普通程序员&#xff0c;要先学会使用&#xff0c;再探究其内部原理。 链表的数据结构&#xff1a; struct list_head {struct list_head *next, *prev; };还有一种&#xff1a;struct h…