java中LinkedList和ArrayList的区别和联系?

我们被要求解释Java中LinkedList和ArrayList的区别和联系。下面将分别从实现原理、性能特点、使用场景等方面进行详细说明,并总结它们的相同点和不同点。
# 一、联系(共同点)
1. 都实现了List接口,因此具有List接口的所有方法,如add, remove, get, set等。
2. 都允许存储重复元素和null值。
3. 都不是线程安全的(可以在外部使用Collections.synchronizedList进行同步包装)。
# 二、区别
## 1. 底层数据结构
- ArrayList:基于动态数组。当数组空间不足时,会自动进行扩容(通常是增加50%的容量)。
- LinkedList:基于双向链表。每个元素(节点)都包含对前一个和后一个元素的引用。
## 2. 性能特点
### a. 随机访问(根据索引访问)
- ArrayList:由于基于数组,可以通过索引直接访问元素,时间复杂度为O(1)。
- LinkedList:需要从链表头或尾开始遍历到指定位置,时间复杂度为O(n)。
### b. 插入和删除
- 在末尾插入:
- ArrayList:平均O(1)(如果不需要扩容,则直接添加;扩容时会有一次O(n)的复制)。
- LinkedList:O(1)(因为维护了尾指针)。
- 在指定位置插入/删除:
- ArrayList:需要移动插入位置后面的所有元素(使用System.arraycopy),平均为O(n)。
- LinkedList:找到指定位置需要O(n),但插入/删除操作本身是O(1)(只需改变相邻节点的引用)。
### c. 内存占用
- ArrayList:每个元素只需要存储实际数据,数组结构本身有少量额外开销(如记录数组大小)。但是,为了避免频繁扩容,通常会预留一些空间(浪费空间)。
- LinkedList:每个元素(节点)需要额外的空间存储前驱和后继引用(每个节点两个引用),因此内存开销更大。
## 3. 其他
- LinkedList还实现了Deque接口,因此可以作为双端队列使用(提供了如addFirst, addLast, removeFirst等方法)。
- ArrayList没有这些方法。
# 三、使用场景
- 当需要频繁随机访问元素时(例如,经常使用get(index)或set(index,element)),使用ArrayList。
- 当需要频繁在列表中间插入和删除元素,并且主要是顺序访问(如使用迭代器)时,使用LinkedList。
- 当需要实现栈、队列或双端队列时,LinkedList更合适(因为它实现了Deque接口)。
# 四、示例代码对比
```java
// ArrayList 示例
List<String> arrayList = new ArrayList<>();
arrayList.add("A"); // 添加到末尾
arrayList.get(0);   // 随机访问快
arrayList.add(1, "B"); // 在指定位置插入,需要移动元素
// LinkedList 示例
List<String> linkedList = new LinkedList<>();
linkedList.add("A");
linkedList.addFirst("B"); // 在头部添加,ArrayList没有此方法
linkedList.get(0); // 随机访问慢,需要遍历
linkedList.add(1, "C"); // 先遍历到位置1,然后插入
```
# 五、总结表格
| 特性                  | ArrayList                     | LinkedList                  |
|----------------------|-------------------------------|-----------------------------|
| 底层数据结构          | 动态数组                      | 双向链表                    |
| 随机访问              | O(1)                          | O(n)                        |
| 头插/头删             | O(n)(需要移动所有元素)       | O(1)                        |
| 尾插/尾删             | O(1)(均摊)                  | O(1)                        |
| 中间插入/删除          | O(n)(移动元素)              | O(n)(查找位置)+ O(1)(操作) |
| 内存占用              | 较少(仅数组开销,可能预留空间)| 较多(每个节点两个引用)      |
| 额外功能              | 无                            | 实现了Deque,有双端队列操作  |
# 六、注意事项
1. 在大多数应用中,ArrayList更常用,因为随机访问快,且通常插入删除操作并不频繁,或者发生在末尾。
2. 如果需要使用LinkedList的特性(如双端队列操作),建议声明为Deque类型,如:`Deque<String> deque = new LinkedList<>();`,这样可以明确使用双端队列的接口。
通过以上分析,我们可以根据具体需求选择使用ArrayList还是LinkedList。
Java中LinkedList与ArrayList的深度解析
一、核心区别对比
特性
ArrayList
LinkedList
底层数据结构
动态数组
双向链表
内存占用
连续内存,空间开销小
节点存储,额外引用空间开销大
随机访问速度
O(1) - 极快
O(n) - 需遍历
头尾插入删除
尾部O(1),头部O(n)
O(1) - 极快
中间插入删除
O(n) - 需移动元素
O(n) - 需遍历到位置
迭代器性能
快速随机访问
顺序访问高效
内存碎片
较少
较多
实现接口
List
List + Deque
二、底层实现原理
1. ArrayList - 动态数组
java

复制

下载
// 简化版ArrayList实现
public class ArrayList<E> {
    private static final int DEFAULT_CAPACITY = 10;
    transient Object[] elementData; // 核心数组
    private int size;
    
    public boolean add(E e) {
        ensureCapacityInternal(size + 1); // 容量检查
        elementData
[size++] = e; // 直接赋值
        return true;
    }
    
    public E get(int index) {
        rangeCheck(index);
        return elementData(index); // 直接索引访问
    }
}
2. LinkedList - 双向链表
java

复制

下载
// 简化版LinkedList实现
public class LinkedList<E> {
    transient Node<E> first;
    transient Node<E> last;
    transient int size = 0;
    
    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;
        }
    }
    
    public boolean add(E e) {
        linkLast(e); // 添加到链表尾部
        return true;
    }
    
    public E get(int index) {
        checkElementIndex(index);
        return node(index).item; // 需要遍历链表
    }
}
三、性能基准测试(10万次操作)
操作
ArrayList
LinkedList
性能差
随机访问(10万次get)
2ms
4200ms
2100倍
头部插入(10万次addFirst)
1200ms
8ms
150倍
尾部插入(10万次add)
5ms
7ms
相近
中间插入(10万次add)
850ms
3500ms
4倍
迭代遍历(10万次)
3ms
4ms
相近
四、典型使用场景
✅ 优先使用ArrayList:
1. 频繁随机访问(如:list.get(index))
2. 主要在尾部添加/删除元素
3. 内存敏感型应用
4. 需要最小化内存占用
✅ 优先使用LinkedList:
1. 频繁在头部插入/删除元素
2. 需要实现栈/队列/双端队列
3. 主要使用迭代器顺序访问
4. 元素数量变化大且主要在两端操作
java

复制

下载
// 队列实现示例
Deque<Integer> queue = new LinkedList<>();
queue
.addLast(1);  // 入队
queue
.removeFirst(); // 出队

// 栈实现示例
Deque<Integer> stack = new LinkedList<>();
stack
.addFirst(1); // 压栈
stack
.removeFirst(); // 弹栈
五、内存结构对比
ArrayList内存布局
text

复制

下载
[元素1][元素2][元素3][空][空][空]...
 ↑           ↑
 数据区      预留空间
LinkedList内存布局
text

复制

下载
节点A       节点B       节点C
[prev|data|next] → [prev|data|next] → [prev|data|next]
   ↑_______________________________↓
六、最佳实践建议
1. 初始化容量:
java

复制

下载
// ArrayList预分配空间
List<String> arrayList = new ArrayList<>(1000);

// LinkedList无需预分配
List<String> linkedList = new LinkedList<>();
2. 遍历优化:
java

复制

下载
// 避免使用随机访问遍历LinkedList
// 错误方式:O(n²)
for (int i = 0; i < list.size(); i++) {
    list
.get(i); 
}

// 正确方式:使用迭代器 O(n)
for (Iterator it = list.iterator(); it.hasNext();) {
    it
.next();
}
3. 批量操作:
java

复制

下载
// ArrayList批量插入优化
arrayList
.addAll(index, collection); // 一次性移动元素

// LinkedList避免在中间批量插入
4. 线程安全:
java

复制

下载
// 两者都非线程安全,需要同步
List syncList = Collections.synchronizedList(new ArrayList());
七、特殊场景分析
1. 内存碎片问题:
◦ ArrayList:内存连续,GC友好
◦ LinkedList:节点分散,可能引起内存碎片
2. CPU缓存友好性:
◦ ArrayList:数据局部性好,CPU缓存命中率高
◦ LinkedList:节点分散,缓存命中率低
3. 大型对象存储:
◦ ArrayList:适合存储小型对象
◦ LinkedList:更适合存储大型对象(减少数组复制开销)
八、JDK优化趋势
在较新JDK版本中(Java 11+):
1. ArrayList在插入时采用更智能的扩容策略
2. LinkedList优化了迭代器实现
3. 新增List.of()创建不可变列表(底层实现根据大小自动选择)
总结选择指南
1. 80%场景选择ArrayList - 现代CPU缓存优化使数组结构在多数操作中表现优异
2. 特定场景选择LinkedList:
◦ 实现先进先出(FIFO)队列
◦ 实现后进先出(LIFO)栈
◦ 需要频繁在列表头部操作
◦ 元素数量变化极大且无法预估
最终建议:在不确定时优先使用ArrayList,仅在明确需要LinkedList特性时才使用它。JDK自身的实现(如ArrayDeque)也倾向于使用数组结构而非链表。

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

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

相关文章

明远智睿SD2351核心板:边缘计算时代的工业级核心引擎深度解析

在工业4.0与物联网深度融合的背景下&#xff0c;边缘计算设备正从单一功能模块向高集成度、智能化平台演进。明远智睿推出的SD2351核心板&#xff0c;凭借其异构计算架构、工业级接口资源和全栈技术生态&#xff0c;重新定义了边缘计算设备的性能边界。本文将从技术架构、场景适…

Flask 动态模块注册

目录 1. 项目概述2. 项目结构3. 核心组件解析3.1 动态模块注册系统 (api/__init__.py)3.2 应用程序入口 (setup_demo.py) 4. 模块开发指南4.1 标准模块 (*_app.py)4.2 SDK模块 (sdk/*.py) 5. URL路径规则6. 如何使用6.1 启动应用6.2 添加新模块 7. 工作原理 1. 项目概述 这个项…

JVM 内存、JMM内存与集群机器节点内存的联系

目录 1、JVM 内存 1.1、分配机制 1.2、jvm模型位置 1.3、字节码内存块 2、JMM内存 2.1、JMM模型 2.2、工作流程图 1、工作内存与主内存的交互 2. 多线程下的主内存与堆内存交互 2.3、 主内存与工作内存的同步方案 1、volatile 2、synchronized 3、final 3、内存使…

学习昇腾开发的第一天--环境配置

1、昇腾社区官网&#xff1a;昇腾社区官网-昇腾万里 让智能无所不及 2、产品-->选择开发者套件-->点击制卡工具的下载&#xff1a;资源-Atlas 200I DK A2-昇腾社区 3、如果制卡工具不能使用在线制卡&#xff0c;可以下载镜像到本地使用本地制卡&#xff1a;Linux系统制…

Android WebView 深色模式适配方案总结

Android WebView 深色模式适配方案总结 在 Android WebView 中适配深色模式&#xff08;Dark Mode&#xff09;是一个常见的需求&#xff0c;尤其是当加载的网页没有原生支持 prefers-color-scheme 时。本文将介绍 3 种主流方案&#xff0c;并分析它们的优缺点&#xff0c;帮助…

项目练习:使用mybatis的foreach标签,实现union all的拼接语句

文章目录 一、需求说明二、需求分析三、代码实现四、报表效果 一、需求说明 在sql查询数据后&#xff0c;对数据分组统计。并最后进行总计。 二、需求分析 最终&#xff0c;我想用sql来实现这个统计和查询的功能。 那么&#xff0c;怎么又查询&#xff0c;又统计了&#xf…

7.7 Extracting and saving responses

Chapter 7-Fine-tuning to follow instructions 7.7 Extracting and saving responses 在本节中&#xff0c;我们保存测试集响应以便在下一节中评分&#xff0c;除此之外保存模型的副本以供将来使用。 ​ 首先&#xff0c;让我们简单看看finetuned模型生成的响应 torch.manu…

计算机网络第3章(上):数据链路层全解析——组帧、差错控制与信道效率

目录 一、数据链路层的功能二、组帧2.1 字符计数法&#xff08;Character Count&#xff09;2.2 字符填充法&#xff08;Character Stuffing&#xff09;2.3 零比特填充法2.4 违规编码法 三、差错控制3.1 检错编码&#xff08;奇偶校验码&#xff09;3.2 循环冗余校验&#xff…

铸铁试验平台的重要性及应用前景

铸铁作为一种重要的金属材料&#xff0c;在工业生产中扮演着举足轻重的角色。为了确保铸铁制品的质量和性能&#xff0c;铸铁材料的试验是必不可少的环节。而铸铁试验平台则是进行铸铁试验的关键设备之一&#xff0c;它为铸铁材料的研究和开发提供了重要的技术支持。本文将探讨…

std::shared_ptr引起内存泄漏的例子

目录 一、循环引用&#xff08;最常见场景&#xff09; 示例代码 内存泄漏原因 二、共享指针管理的对象包含自身的 shared_ptr 示例代码 内存泄漏&#xff08;或双重释放&#xff09;原因 三、解决方案 1. 循环引用&#xff1a;使用 std::weak_ptr 2. 对象获取自身的 …

AI 知识数据库搭建方案:从需求分析到落地实施

AI 知识数据库的搭建需结合业务场景、数据特性与技术架构&#xff0c;形成系统化解决方案。以下是一套完整的搭建框架&#xff0c;涵盖规划、设计、实施及优化全流程&#xff1a; 一、前期规划&#xff1a;需求分析与目标定义 1. 明确业务场景与知识需求 场景导向&#xff1a…

Tensorflow 基础知识:变量、常量、占位符、Session 详解

在深度学习领域,TensorFlow 是一个广泛使用的开源机器学习框架。想要熟练使用 TensorFlow 进行模型开发,掌握变量、常量、占位符和 Session 这些基础知识是必不可少的。接下来,我们就深入了解一下它们的概念、用处,并通过代码示例进行演示。 一、常量(Constant) 常量,顾…

linux 常见问题之如何清除大文件的内容

linux 常见问题之如何清除大文件的内容 在 Linux 系统中&#xff0c;我们有时会遇到文件随着时间增长变得巨大&#xff0c;最常见的就是服务器的日志文件&#xff0c;随着时间的推移占用大量的磁盘空间&#xff0c;下面介绍如何清楚大文件的内容&#xff0c;当然避免文件内容过…

薛定谔的猫思想实验如何推演到量子计算

前言 这是我的选修课作业&#xff0c;但是我并不喜欢小论文方式的写法&#xff0c;死板又老套。先在这打一份底稿。 薛定谔的猫 可能一说到量子这个关键词&#xff0c;大家第一时间都会想到的是“薛定谔的猫”。 实验介绍 薛定谔的猫是一个著名的思想实验&#xff0c;由奥…

嵌入式开发中fmacro-prefix-map选项解析

在嵌入式开发中&#xff0c;-fmacro-prefix-map 是 GCC 和 Clang 等编译器提供的一个路径映射选项&#xff0c;主要用于在预处理阶段重写宏定义中出现的绝对路径。它的核心目的是解决以下问题&#xff1a; 核心作用 构建可重现性 消除编译输出&#xff08;如 .o、.d 文件&…

Javaweb学习——day3(Servlet 中处理表单数据)

文章目录 一、概念学习1. GET vs POST 请求方式的区别2. HttpServletRequest 获取表单数据 二、代码讲解与练习第 1 步&#xff1a;在 webapp 下创建 login.html第 2 步&#xff1a;在 com.example 包下创建 LoginServlet第 3 步&#xff1a;修改 web.xml 注册 LoginServlet第 …

在 iOS 开发中单独解析域名为 IP

1 为什么要自己解析? 典型场景说明劫持/污染检测比较 系统解析 与 自建 DNS 的差异QoS / CDN 选路对每个候选 IP 做 RT/丢包测速系统 API(NSURLSession / Network.framework)在「真正建立连接之前」不会把解析结果暴露出来,因此需要主动解析一步。 2 API 选型概览 API是否过…

YOLOv1 技术详解:正负样本划分与置信度设计

&#x1f50d; YOLOv1 技术详解&#xff1a;正负样本划分与置信度设计 一、前言 YOLOv1 是目标检测领域中具有划时代意义的算法之一&#xff0c;它将检测任务统一为一个回归问题&#xff0c;实现了“You Only Look Once”的端到端实时检测。其中&#xff0c;正负样本的划分机…

为 Nginx 配置 HTTPS(以 n8n 为例)完整教程【CentOS 7】

在部署如 n8n 这类自动化平台时&#xff0c;为了保障数据传输安全&#xff0c;我们通常会使用 HTTPS 访问。本文将以 n8n.example.com 为例&#xff0c;介绍如何在 CentOS 7 系统中通过 Nginx 为本地运行在端口 5678 的 n8n 服务配置免费 SSL 证书&#xff08;Let’s Encrypt&a…

Elasticsearch从安装到实战、kibana安装以及自定义IK分词器/集成整合SpringBoot详细的教程ES(四)查询、排序、分页、高亮

基础代码 package com.test.xulk;import com.alibaba.fastjson.JSON; import com.test.xulk.es.esdoc.HotelDoc; import com.test.xulk.es.service.IHotelService; import org.apache.http.HttpHost; import org.elasticsearch.action.search.SearchRequest; import org.elast…