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

news2024/12/17 23:18:54

目录

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.coloradmin.cn/o/2261294.html

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

相关文章

阿里云服务器手动部署LNMP环境【官方文档注意事项】

这是官方文档 注意&#xff1a; 要添加安全组&#xff0c;端口为80。否则最后用浏览器访问公网IP没有结果。 Mysql密码策略要求密码至少包含一个大写字母、一个小写字母、一个数字和一个特殊字符&#xff0c;并且密码总长度至少为 8 个字符。sudo mysqladmin -uroot -p<ol…

Invalid default value for ‘gender‘,mysql在idea中字符集设置,default

默认值default创建错误的&#xff0c;设置数据库字符集 我的错误&#xff1a;Invalid default value for ‘gender’ -- 修改数据库字符集 alter database db01 charset utf8;

240004基于Jamva+ssm+maven+mysql的房屋租赁系统的设计与实现

基于ssmmavenmysql的房屋租赁系统的设计与实现 1.项目描述2.运行环境3.项目截图4.源码获取 1.项目描述 该项目在原有的基础上进行了优化&#xff0c;包括新增了注册功能&#xff0c;房屋模糊查询功能&#xff0c;管理员和用户信息管理等功能&#xff0c;以及对网站界面进行了优…

使用Navicat从SQL Server导入表数据到MySQL

在表上右键选择导入向导 选择ODBC 1.内输入ip即可&#xff0c;不需要端口号 一定要勾选允许保存密码 选择需要的表&#xff0c;下一步 根据需求&#xff0c;可修改表名、是否新建表 根据需求修改不同表的字段类型和长度 按需选择导入方式

STM32F407+LAN8720A +LWIP +FreeRTOS ping通

使用STM32CUBEIDE自带的 LWIP和FreeROTS 版本说明STM32CUBEIDE 操作如下1. 配置RCC/SYS2. 配置ETH/USART3. 配置EHT_RESET/LED4. 配置FreeRTOS5. 配置LWIP6. 配置时钟7. 生成单独的源文件和头文件,并生成代码8. printf重定义9. ethernetif.c添加lan8720a复位10. MY_LWIP_Init …

用 Python Turtle 绘制经典汤姆猫:重温卡通角色的经典魅力

用 Python Turtle 绘制经典汤姆猫&#xff1a;重温卡通角色的经典魅力 &#x1f438; 前言 &#x1f438;&#x1f41e;往期绘画>>点击进所有绘画&#x1f41e;&#x1f40b; 效果图 &#x1f40b;&#x1f409; 代码 &#x1f409; &#x1f438; 前言 &#x1f438; 汤…

RabbitMQ个人理解与基本使用

目录 一. 作用&#xff1a; 二. RabbitMQ的5中队列模式&#xff1a; 1. 简单模式 2. Work模式 3. 发布/订阅模式 4. 路由模式 5. 主题模式 三. 消息持久化&#xff1a; 消息过期时间 ACK应答 四. 同步接收和异步接收&#xff1a; 应用场景 五. 基本使用 &#xff…

Y3编辑器文档4:触发器1(界面及使用简介、变量作用域、入门案例)

文章目录 一、触发器简介1.1 触发器界面1.2 ECA语句编辑及快捷键1.3 参数设置1.4 变量设置1.5 实体触发器1.6 触发器复用 二、触发器的多层结构2.1 子触发器&#xff08;在游戏内对新的事件进行注册&#xff09;2.2 触发器变量作用域 三、入门案例3.1 使用触发器实现瞬间移动3.…

【DBeaver】连接带kerberos的hive[Apache|HDP]

目录 一、安装配置Kerberos客户端环境 1.1 安装Kerberos客户端 1.2 环境配置 二、基于Cloudera驱动创建连接 三、基于Hive原生驱动创建连接 一、安装配置Kerberos客户端环境 1.1 安装Kerberos客户端 在Kerberos官网下载,地址如下&#xff1a;https://web.mit.edu/kerberos…

bug:uniapp运行到微信开发者工具 白屏 页面空白

1、没有报错信息 2、预览和真机调试都能正常显示&#xff0c;说明代码没错 3、微信开发者工具版本已经是win7能装的最高版本了&#xff0c;1.05版 链接 不打算回滚旧版本 4、解决&#xff1a;最后改调试基础库为2.25.4解决了&#xff0c;使用更高版本的都会报错&#xff0c;所…

【前端】JavaScript自定义 forEach方法详解与原理分析

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: 前端 文章目录 &#x1f4af;前言&#x1f4af;题目演示与效果演示代码控制台输出结果 &#x1f4af;代码分析与源理解释1. 构造函数 Brray2. 实例化 Brray3. 调用自定义的 forEach &#x1f4af;比较与拓展1. 比较原…

基于卷积神经网络的Caser算法

将一段交互序列嵌入到一个以时间为纵轴的平面空间中形成“一张图”后&#xff0c;基于卷积序列嵌入的推荐&#xff08;Caser&#xff09;算法利用多个不同大小的卷积滤波器&#xff0c;来捕捉序列中物品间的点级&#xff08;point-level&#xff09;、联合的&#xff08;union-…

挑战一个月基本掌握C++(第三天)了解注释、数据类型、变量

一 C注释 程序的注释是解释性语句&#xff0c;您可以在 C 代码中包含注释&#xff0c;这将提高源代码的可读性。所有的编程语言都允许某种形式的注释。 C 支持单行注释和多行注释。注释中的所有字符会被 C 编译器忽略。 C 注释一般有两种&#xff1a; // - 一般用于单行注释…

211-基于FMC的1路1.5G ADC 1路 2.5G DAC子卡

一、板卡概述 FMC-1AD-1DA-1SYNC是我司自主研发的一款1路1G AD采集、1路2.5G DA回放的FMC、1路AD同步信号子卡。板卡采用标准FMC子卡架构&#xff0c;可方便地与其他FMC板卡实现高速互联&#xff0c;可广泛用于高频模拟信号采集等领域。 二、功能介绍 2.1 原理框图 2.2 硬件…

Cloudlog 电台日志系统 request_form SQL注入漏洞复现

0x01 产品简介 Cloudlog 是一个自托管的 PHP 应用程序,可让您在任何地方记录您的业余无线电联系人。使用PHP和MySQL构建的基于Web的业余无线电记录应用程序支持从HF到微波的一般站记录任务。 0x02 漏洞概述 Cloudlog request_form 接口存在未授权SQL注入漏洞,未经身份验证…

Jenkins容器使用宿主机Docker(五)

DevOps之安装和配置 Jenkins (一) DevOps 之 CI/CD入门操作 (二) Sonar Qube介绍和安装&#xff08;三&#xff09; Harbor镜像仓库介绍&安装 &#xff08;四&#xff09; Jenkins容器使用宿主机Docker&#xff08;五&#xff09; Jenkins流水线初体验&#xff08;六&#…

【大模型】LLaMA-2:Open Foundation and Fine-Tuned Chat Models, July. 2023.

论文&#xff1a;LLaMA-2&#xff1a;Open Foundation and Fine-Tuned Chat Models, July. 2023. 链接&#xff1a;https://arxiv.org/abs/2307.09288 Introduction 创新点 7B - 70B 预训练 微调 开源Llama 2 和Llama 2-Chat&#xff0c;针对对话用例进行了优化Motivation A…

Jmeter直连数据库,jar包下载

运行报错信息&#xff1a;jmeter连接mysql异常&#xff1a;Cannot load JDBC driver class ‘com.mysql.jdbc.Driver‘ 1、下载地址&#xff1a; https://mvnrepository.com/artifact/mysql/mysql-connector-java/ 2、将下载好的jar包 &#xff08;我的是&#xff1a;mysql-con…

安全攻击平台介绍

目录 XSS攻击平台 Attack API BeEF XSS-Proxy 漏洞平台 cnvd 阿里云漏洞库 攻防演练平台 XCTF 攻防平台 零日靶场&#xff08;0ops&#xff09; 安恒靶场&#xff08;赛宁安全&#xff09; XSS攻击平台 XSS Payload如此强大&#xff0c;为了使用方便&#xff0c;有安…