ArrayList源码分析、扩容机制面试题,数组和List的相互转换,ArrayList与LinkedList的区别

目录

1.java集合框架体系

2. 前置知识-数组

2.1 数组

2.1.1 定义:

2.1.2 数组如何获取其他元素的地址值?(寻址公式)

2.1.3 为什么数组索引从0开始呢?从1开始不行吗?

3. ArrayList

3.1 ArrayList和和Vector的区别?(了解)

3.2 ArrayList 可以添加 null 值吗?

3.3 ArrayList源码

成员变量

​编辑构造方法

3.4 ArrayList 底层实现原理 ★

3.5 ArrayList list = new ArrayList(10)中的list扩容几次?★

3.6 数组和List之间相互转换?★

3.7 数组和List之间相互转换过程中,数据发生修改,结果会变吗(有影响吗)?★

3.7.1  用Arrays.asList() 转List后,如修改了数组内容,list集合结果受影响吗?

3.7.2 List用toArray() 转数组后,如果修改了List内容,数组受影响吗?

4. 前置知识-链表

4.1单向链表

4.1.1 单向链表特点及参考源码

4.1.2 单向链表时间复杂度分析

1 查询操作

2 插入和删除操作

4.2 双向链表

4.2.1 双向链表特点及参考源码

4.2.2 双向链表时间复杂度分析

1. 查询操作

2 增删操作

5. LinkedList

6. ArrayList与LinkedList区别?★


1.java集合框架体系

2. 前置知识-数组

2.1 数组

2.1.1 定义:

数组(Array)是一种用连续内存空间存储相同数据类型数据的线性数据结构。

int[] array = {22,33,88,66,55,25};

2.1.2 数组如何获取其他元素的地址值?(寻址公式

在数组在内存中查找元素的时候,是有一个寻址公式的,如下:
arr[i] = baseAddress + i * dataTypeSize

2.1.3 为什么数组索引从0开始呢?从1开始不行吗?

实际上并不是不行。而是如果数组索引从1开始的话,整体性能会变低。
因为寻址公式会变为a[i] = baseAddress + (i-1) *dataTypeSize,也就是说,多了一个减法操作。

3. ArrayList

ArrayList 的底层是数组队列,相当于动态数组。与 Java 中的数组相比,它的容量能动态增长。在添加大量元素前,应用程序可以使用ArrayList底层API的 ensureCapacity()操作来增加 ArrayList 实例的容量。这可以减少递增式再分配的数量。

 

3.1 ArrayList和和Vector的区别?(了解)

  • ArrayList 是 List 的主要实现类,底层使用 Object[]存储,适用于频繁的查找工作,线程不安全 。  

  • Vector 是 List 的古老实现类,底层使用Object[] 存储,线程安全。

3.2 ArrayList 可以添加 null 值吗?

可以。ArrayList 中可以存储任何类型的对象,包括 null 值。不过,不建议向ArrayList 中添加 null 值, null 值无意义,会让代码难以维护比如忘记做判空处理就会导致空指针异常。

3.3 ArrayList源码

成员变量

构造方法

第一个构造是带初始化容量的构造函数,可以按照指定的容量初始化数组
第二个是无参构造函数,默认创建一个空集合
/***构造包含指定collection元素的列表,这些元素利用该集合的迭代器按顺序返回*如果指定的集合为null,throws NullPointerException。*/
public ArrayList(Collection<? extends E> c) {elementData = c.toArray();if ((size = elementData.length) != 0) {if (elementData.getClass() != Object[].class)elementData = Arrays.copyOf(elementData, size, Object[].class);} else {// replace with empty array.this.elementData = EMPTY_ELEMENTDATA;}
}
collection 对象转换成数组,然后将数组的地址的赋给 elementData

3.4 ArrayList 底层实现原理 ★

1. 底层数据结构

ArrayList 底层是用动态的数组实现的

2. 初始容量

ArrayList 初始容量为 0 ,当第一次添加数据的时候才会初始化容量为 10

3. 扩容逻辑

ArrayList 在进行扩容的时候是原来容量的 1.5 倍,每次扩容都需要拷贝数组

4. 添加逻辑

添加数据的流程:

1. 确保数组已使用长度( size )加 1 之后足够存下下一个数据
2. 计算数组的容量,如果当前数组已使用长度 +1 后的大于当前的数组长度,
3. 则调用 grow 方法扩容(原来的 1.5 倍)
4. 确保新增的数据有地方存储之后,则将新元素添加到位于 size 的位置上。
5. 返回添加成功布尔值。

3.5 ArrayList list = new ArrayList(10)中的list扩容几次?

答:该语句只是声明和实例了一个 ArrayList ,指定了容量为 10 ,未扩容

ArrayList的扩容机制如下:

  1. ArrayList被初始化时,如果没有指定初始容量,它将使用默认的初始容量(10)。

  2. 当添加元素超过当前容量时,ArrayList会进行扩容。默认情况下,扩容后的容量是当前容量的1.5倍(即增加50%)。

3.6 数组和List之间相互转换?★

参考回答:

  • 数组转List ,使用JDKjava.util.Arrays工具类的asList方法,返回一个List集合
  • List转数组,使用ListtoArray方法。无参toArray方法返回 Object数组,传入初始化长度的数组对象,返回该对象数组

3.7 数组和List之间相互转换过程中,数据发生修改,结果会变吗(有影响吗)?★

分为两种情况:

3.7.1  用Arrays.asList() 转List后,如修改了数组内容,list集合结果受影响吗?

答:会受影响

Arrays.asList 方法返回的是一个固定大小的列表,它的底层仍然是原始数组。

当你通过 Arrays.asList 获得的列表并尝试修改其中的元素时,实际上是在修改原始数组的内容,因为列表中的元素和数组中的元素是同一个对象(同一个地址引用)。

源码如下:

3.7.2 List用toArray() 转数组后,如果修改了List内容,数组受影响吗?

答:不会影响。

list用了toArray转数组后,如果修改了list内容,数组不会影响,当调用了toArray  以后,在底层是它是进行了数组的拷贝,跟原来的元素就没啥关系了,所以即使  list修改了以后,数组

也不受影响

4. 前置知识-链表

LinkedList 底层数据结构——双向链表

4.1单向链表

4.1.1 单向链表特点及参考源码

  • 链表中的每一个元素称之为结点(Node
  • 物理存储单元上,非连续、非顺序的存储结构
  • 单向链表:每个结点包括两个部分:一个是存储数据元素的数据域,另一个 是存储下一个结点地址的指针域。记录下个结点地址的指针叫作后继指针next

代码实现参考:

4.1.2 单向链表时间复杂度分析

1 查询操作

查询:头节点:O(1),一般情况:O(n)
  • 只有在查询头节点的时候不需要遍历链表,时间复杂度是O(1)
  • 查询其他结点需要遍历链表,时间复杂度是O(n)
2 插入和删除操作

增删:头节点:O(1),一般情况:O(n)

  • 只有在添加和删除头节点的时候不需要遍历链表,时间复杂度是O(1)
  • 添加或删除其他结点需要遍历链表找到对应节点后,才能完成新增或删除节点,时间复杂度是O(n)

4.2 双向链表

4.2.1 双向链表特点及参考源码

而双向链表,顾名思义,它支持两个方向
  • 每个结点不止有一个后继指针 next 指向后面的结点
  • 有一个前驱指针 prev 指向前面的结点
代码实现参考:

4.2.2 双向链表时间复杂度分析

1. 查询操作

查询:头尾节点:O(1),一般情况:O(n),给定节点找前驱节点:O(1)

  • 查询头尾结点的时间复杂度是O(1)
  • 平均的查询时间复杂度是O(n)
  • 给定节点找前驱节点的时间复杂度为O(1)
2 增删操作
增删:头尾节点:O(1),一般情况:O(n),给定节点找前驱节点:O(1)
  • 头尾结点增删的时间复杂度为O(1)
  • 其他部分结点增删的时间复杂度是 O(n)
  • 给定节点增删的时间复杂度为O(1)

5. LinkedList

LinkedList 底层数据结构——双向链表

查询快,增删改慢,适用于读多写少的场景

6. ArrayList与LinkedList区别?★

从四个方面来谈。

  • 底层数据结构:ArrayList 是动态数组的数据结构实现,LinkedList 是双向链表的数据结构实现
  • 效率上,除了 LinkedList不支持下标查询,ArrayList支持下标查询。其他都差不多。
  • 空间上,ArrayList底层是数组,内存连续,节省内存。LinkedList 是双向链表需要存储数据,和两个指针,更占用内存。
  • 线程安全问题,ArrayList和LinkedList都不是线程安全的。

如果需要保证线程安全,有两种方案:

  • 在方法内使用,局部变量则是线程安全的
  • 使用线程安全的ArrayList和LinkedList:
Collections.synchronizedList(new ArrayList<>());
Collections.synchronizedList(new LinkedList<>());

还有一下三个方面的区别可以了解一下:

  • 插入和删除是否受元素位置的影响:
    • ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。 比如:执行add(E e)方法的时候, ArrayList 会默认在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是 O(1)。但是如果要在指定位置 i 插入和删除元素的话(add(int index, E element)),时间复杂度就为 O(n)。因为在进行上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的操作。
    • LinkedList 采用链表存储,所以在头尾插入或者删除元素不受元素位置的影响(add(E e)addFirst(E e)addLast(E e)removeFirst()、 removeLast()),时间复杂度为 O(1),如果是要在指定位置 i 插入和删除元素的话(add(int index, E element)remove(Object o),remove(int index)), 时间复杂度为 O(n) ,因为需要先移动到指定位置再插入和删除。
  • 是否支持快速随机访问: LinkedList 不支持高效的随机元素访问,而 ArrayList(实现了 RandomAccess 接口) 支持。快速随机访问就是通过元素的序号快速获取元素对象(对应于get(int index)方法)。
  • 内存空间占用: ArrayList 的空间浪费主要体现在在 list 列表的结尾会预留一定的容量空间,而 LinkedList 的空间花费则体现在它的每一个元素都需要消耗比 ArrayList 更多的空间(因为要存放直接后继和直接前驱以及数据)。

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

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

相关文章

【C++】- 掌握STL List类:带你探索双向链表的魅力

文章目录 前言&#xff1a;一.list的介绍及使用1. list的介绍2. list的使用2.1 list的构造2.2 list iterator的使用2.3 list capacity2.4 list element access2.5 list modifiers2.6 list的迭代器失效 二.list的模拟实现1. list的节点2. list的成员变量3.list迭代器相关问题3.1…

Docker--Docker Container(容器) 之容器实战

对docker容器的前两篇文章 Docker–Docker Container(容器) 之 操作实例 Docker–Docker Container(容器&#xff09; Mysql容器化安装 我们可以先在Docker Hub上查看对应的Mysql镜像,拉取对应的镜像&#xff1a; 拉取mysql5.7版本的镜像&#xff1a; docker pull mysql:5.7…

【汇编语言】内中断(二) —— 安装自己的中断处理程序:你也能控制0号中断

文章目录 前言1. 编程处理0号中断1.1 效果演示1.2 分析所要编写的中断处理程序1.2.1 引发中断1.2.2 中断处理程序1.2.3 中断处理程序do0应该存放的位置1.2.4 中断向量表的修改1.2.5 总结 1.3 程序框架1.4 注意事项1.5 从CPU的角度看中断处理程序1.6 一些问题的思考与解答 2. 安…

VS2019中无法跳转定义_其中之一情况

我习惯了使用VS2019看stm的代码&#xff1b; 遇到的问题&#xff0c;在导入代码后&#xff0c;发现有些函数调用不能跳转到定义&#xff1b; 问题描述步骤 1、导入代码 2、跳转&#xff0c;无法跳转 1、中文路径 2、删除.vs文件 和网上查的都没办法解决 最后发现是VS不支持 …

让 Win10 上网本 Debug 模式 QUDPSocket 信号槽 收发不丢包的方法总结

在前两篇文章里&#xff0c;我们探讨了不少UDP丢包的解决方案。经过几年的摸索测试&#xff0c;其实方法非常简单, 无需修改代码。 1. Windows 下设置UDP缓存 这个方法可以一劳永逸解决UDP的收发丢包问题&#xff0c;只要添加注册表项目并重启即可。即使用Qt的信号与槽&#…

Elasticsearch:ES|QL 中的全文搜索 - 8.17

细心的开发者如果已经阅读我前两天发布的文章 “Elastic 8.17&#xff1a;Elasticsearch logsdb 索引模式、Elastic Rerank 等”&#xff0c;你就会发现在 8.17 的发布版中&#xff0c;有一个重要的功能发布。那就是 ES|QL 开始支持全文搜索了。在今天的文章中我们来尝试一下。…

SQL和Python 哪个更容易自学?

SQL和Python不是一个物种&#xff0c;Python肯定更难学习。如果你从事数据工作&#xff0c;我建议先学SQL、有余力再学Python。因为SQL不光容易学&#xff0c;而且前期的投入产出比更大。 SQL是数据查询语言&#xff0c;场景限于数据查询和数据库的管理&#xff0c;对大部分数据…

【unity】从零开始制作平台跳跃游戏--界面的认识,添加第一个角色!

在上一篇文章中&#xff0c;我们已经完成了unity的环境配置与安装⬇️ 【Unity】环境配置与安装-CSDN博客 接下来&#xff0c;让我们开始新建一个项目吧&#xff01; 新建项目 首先进入unityHub的项目页面&#xff0c;点击“新项目”&#xff1a; 我们这个系列将会以2D平台…

怎么禁用 vscode 中点击 go 包名时自动打开浏览器跳转到 pkg.go.dev

本文引用怎么禁用 vscode 中点击 go 包名时自动打开浏览器跳转到 pkg.go.dev 在 vscode 设置项中配置 gopls 的 ui.navigation.importShortcut 为 Definition 即可。 "gopls": {"ui.navigation.importShortcut": "Definition" }ui.navigation.i…

Unity3D实现抽象类的应用场景例子

系列文章目录 unity知识点 文章目录 系列文章目录👉前言👉一、示例👉二、使用步骤👉三、抽象类和接口的区别👉3-1、抽象类👉3-2、接口类👉壁纸分享👉总结👉前言 假设我们正在制作一个游戏,游戏中有多种不同类型的角色,这些角色都有一些共同的行为(比如移…

数据仓库工具箱—读书笔记01(数据仓库、商业智能及维度建模初步)

数据仓库、商业智能及维度建模初步 记录一下读《数据仓库工具箱》时的思考&#xff0c;摘录一些书中关于维度建模比较重要的思想与大家分享&#x1f923;&#x1f923;&#x1f923; 博主在这里先把这本书"变薄"~有时间的小伙伴可以亲自再读一读&#xff0c;感受一下…

docker启动一个helloworld(公司内网服务器)

这里写目录标题 容易遇到的问题&#xff1a;1、docker连接问题 我来介绍几种启动 Docker Hello World 的方法&#xff1a; 最简单的方式&#xff1a; docker run hello-world这会自动下载并运行官方的 hello-world 镜像。 使用 Nginx 作为 Hello World&#xff1a; docker…

基于IEEE 802.1Qci的时间敏感网络(TSN)主干架构安全分析及异常检测系统设计

中文标题&#xff1a;基于IEEE 802.1Qci的时间敏感网络&#xff08;TSN&#xff09;主干架构安全分析及异常检测系统设计 英文标题&#xff1a;Security Analysis of the TSN Backbone Architecture and Anomaly Detection System Design Based on IEEE 802.1Qci 作者信息&…

怎样提升企业网络的性能?

企业网络的稳定性和高效性直接影响员工的工作效率。以下从多维度分析了一些有效策略&#xff0c;帮助公司提升网络性能&#xff0c;营造更高效的办公环境。 1. 升级网络设备 采用性能更高的网络硬件是优化网络体验的重要基础。选择支持高吞吐量、低延迟的设备&#xff08;如企业…

力扣239.滑动窗口最大值

文章目录 一、前言二、单调队列 一、前言 力扣239.滑动窗口最大值 滑动窗口最大值&#xff0c;这道题给定一个数组&#xff0c;以及一个窗口的长度&#xff0c;这个窗口会往后滑动&#xff0c;直到数组最后一个元素。 要求每个滑动窗口的中的最大值。对于这道题&#xff0c;我…

mac 安装CosyVoice (cpu版本)

CosyVoice 介绍 CosyVoice 是阿里研发的一个tts大模型 官方项目地址&#xff1a;https://github.com/FunAudioLLM/CosyVoice.git 下载项目&#xff08;非官方&#xff09; git clone --recursive https://github.com/v3ucn/CosyVoice_for_MacOs.git 进入项目 cd CosyVoic…

Maven 安装配置(详细教程)

文章目录 一、Maven 简介二、下载 Maven三、配置 Maven3.1 配置环境变量3.2 Maven 配置3.3 IDEA 配置 四、结语 一、Maven 简介 Maven 是一个基于项目对象模型&#xff08;POM&#xff09;的项目管理和自动化构建工具。它主要服务于 Java 平台&#xff0c;但也支持其他编程语言…

Scala中的泛型特质

代码如下&#xff1a; package test41 //泛型特质 object test3 { //定义一个日志//泛型特质&#xff0c;X是泛型名称&#xff0c;可以更改。trait Logger[X] {val content: Xdef show():Unit }class FileLogger extends Logger[String] {override val content: String "…

ASP.NET |日常开发中读写XML详解

ASP.NET &#xff5c;日常开发中读写XML详解 前言一、XML 概述1.1 定义和结构1.2 应用场景 二、读取 XML 文件2.1 使用XmlDocument类&#xff08;DOM 方式&#xff09;2.2 使用XmlReader类&#xff08;流方式&#xff09; 三、写入 XML 文件3.1 使用XmlDocument类3.2 使用XmlWr…

分布式 Paxos算法 总结

前言 相关系列 《分布式 & 目录》《分布式 & Paxos算法 & 总结》《分布式 & Paxos算法 & 问题》 参考文献 《图解超难理解的 Paxos 算法&#xff08;含伪代码&#xff09;》《【超详细】分布式一致性协议 - Paxos》 Basic-Paxos 基础帕克索斯算法…