java面试基础 -- ArrayList 和 LinkedList有什么区别, ArrayList和Vector呢?
目录
基本介绍
有什么不同??
ArrayList的扩容机制
ArrayLIst的基本使用
ArrayList和Vector
基本介绍
还记得我们的java集合框架吗, 我们来复习一下, 如图:

可以看出来 ArrayList和LinkedList 都是具体类, 他们都是接口List的实现类.
但是他们底层的逻辑是不同的, 相信学过这个的应该大概有个映像吧, 如下图:

可以看出来, ArrayList是向内存申请一块连续的数组空间进行存储, 在数组的存储形式的基础上进行链表的增删改查, 而LinkedList则是每次添加元素的时候就向系统申请一块内存, 不用就直接释放, 他们虽然在内存上不是连续的, 但是在逻辑上他们是连在一起的.
有什么不同??
- 底层实现不同, ArrayList是基于动态数组的数据结构, 而LInkedLIst是基于链表的数据结构
- 随机访问的性能不同, Arraylist的随机访问性能是由于LinkedList的, 因为ArrayList可以根据下标来直接访问, 类似于数组, 时间复杂度为O(1), 但是LinkedList的随机访问时间复杂度为O(n), 因为他需要遍历整个链表才能找到指定的元素
- 插入和删除不同, 对于插入和删除, LInkedList要明显由于ArrayList, 因为LInkedList的掺入和删除操作时间复杂度为O(1), 例如插入, 我们可以直接在链表的头部进行插入或者是通过一个元素来记录最后一个结点的位置, 然后直接在最后一个结点进行尾插, 删除是相同的操作, 因此时间复杂度为O(1), 但是对于ArrayList就不同了, ArrayList的插入和删除需要移动插入位置的元素的后面的所有元素, 最坏的情况需要移动ArrayList的所有元素, 因此时间复杂度为O(n)
小结:
ArrayList 和 LinkedList 都是 List 接口的实现类,但它们的底层实现(结构)不同、随机访问的性能和添加/删除的效率不同。如果是随机访问比较多的业务场景可以选择使用 ArrayList,如果添加和删除比较多的业务场景可以选择使用 LinkedList。
ArrayList的扩容机制
我们首先创建一个ArrayList如图:
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;public class Test {public static void main(String[] args) {List<Integer> arrayList = new ArrayList<>(); // 第0步:创建基于链表的ListarrayList.add(1); // 1 添加元素arrayList.add(2); // 2 添加元素arrayList.add(3); // 3 添加元素arrayList.add(4); // 4 添加元素arrayList.add(5); // 5 添加元素arrayList.add(6); // 6 添加元素arrayList.add(7); // 7 添加元素arrayList.add(8); // 8 添加元素arrayList.add(9); // 9 添加元素System.out.println("hello"); // 打印}
}
第0步, 初始化:
![]()
ArrayList的构造方法如下:
/*** Constructs an empty list with the specified initial capacity.** @param initialCapacity the initial capacity of the list* @throws IllegalArgumentException if the specified initial capacity* is negative*/public ArrayList(int initialCapacity) {if (initialCapacity > 0) {this.elementData = new Object[initialCapacity];} else if (initialCapacity == 0) {this.elementData = EMPTY_ELEMENTDATA;} else {throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);}}/*** Constructs an empty list with an initial capacity of ten.*/public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}/*** Constructs a list containing the elements of the specified* collection, in the order they are returned by the collection's* iterator.** @param c the collection whose elements are to be placed into this list* @throws NullPointerException if the specified collection is null*/public ArrayList(Collection<? extends E> c) {elementData = c.toArray();if ((size = elementData.length) != 0) {// c.toArray might (incorrectly) not return Object[] (see 6260652)if (elementData.getClass() != Object[].class)elementData = Arrays.copyOf(elementData, size, Object[].class);} else {// replace with empty array.this.elementData = EMPTY_ELEMENTDATA;}}
里面有三个重载的构造方法, 简单来说就是:
- 无参构造: Obeject数组elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
- 给定初始容量:
①当 传入的初始容量initialCapacity > 0为真时,创建一个大小为initialCapacity的空数组,并将引用赋给elementData;
②当 传入的初始容量initialCapacity = 0为真时,将空数组EMPTY_ELEMENTDATA赋给elementData;
③当 传入的初始容量initialCapacity < 0为真时,直接抛出IllegalArgumentException异常。
此处我们传入的initialCapacity为空, 也就是无参构造方法, 如下:
transient Object[] elementData;private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
在构造方法中,它将DEFAULTCAPACITY_EMPTY_ELEMENTDATA赋值给elementData,这个DEFAULTCAPACITY_EMPTY_ELEMENTDATA是一个空的Object数组,而elementData就是ArrayList实际存储数据的容器。
第1步, 添加元素1:
触发:
public boolean add(E e) {ensureCapacityInternal(size + 1); // Increments modCount!!elementData[size++] = e;return true;}
ensureCapacityInternal为确认初始化容量:
进入ensureCapacityInternal:
private void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));}
随后进入calculateCapacity计算最低所需容量:
private static int calculateCapacity(Object[] elementData, int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {return Math.max(DEFAULT_CAPACITY, minCapacity);}return minCapacity;}
此处的minCapacity为 size + 1, 翻译过来也就是最低所需的容量, 研究发现, 如果是空数组(刚开始使用无参构造方法的时候)就返回DEFAULT_CAPACITY, 值为10.
当elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA 的时候, 直接返回minCapacity.
随后进入ensureExplicitCapacity(int minCapacity)方法:
private void ensureExplicitCapacity(int minCapacity) {modCount++;// overflow-conscious codeif (minCapacity - elementData.length > 0)grow(minCapacity);}
modCount++,这是用来记录数组被修改次数的变量,我们先不管它. minCapacity为计算出来的最小所需容量, elementData.length为当前容量,如果最小所需容量大于当前容量, 就需要扩容, 然后进入grow方法:
private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1);if (newCapacity - minCapacity < 0)newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// minCapacity is usually close to size, so this is a win:elementData = Arrays.copyOf(elementData, newCapacity);}
老的容量为当前容量,新的容量为老的容量的1.5倍,如果新的容量–最小所需容量<О那么新的容量就等于最小所需容量,如果新的容量-当前数组最大的容量限制>0,那么就进入hugeCapacity方法,然后使用copyOf方法进行数据迁移.将老的数据迁移到新的容量的数组中
总结一下:
我们使用无参构造方法的时候, 就会创建一个底层为空的数组的链表, 此时size 为0, 然后向里面添加元素的时候, 此时的minCapacity为 size + 1 = 1, 在calculateCapacity方法中返回了DEFAULT_CAPACITY(10), 然后进入ensureExplicitCapacity(10), 此时的minCapacity = 10 > 当前容量 = 0, 所以进行初始扩容(elementData = Arrays.copyOf(elementData, newCapacity)), 将容量扩充到10, 也就是elementData/length == 10, 随后的插入, 只要没有超过10, 那就可以直接插入, 如果容量满了, 那么就进行1.5倍扩容.

ArrayLIst的基本使用
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;public class Test {public static void main(String[] args) {ArrayList<Integer> arrayList = new ArrayList<>(); // 第0步:创建基于链表的List// add(int x) 直接向元素末尾位置添加xarrayList.add(1);// get(int index) 方法, 返回下标为index的元素int a = arrayList.get(0);System.out.println(a);// add(int index, int element); 向指定位置插入元素arrayList.add(1,3);// size(); 获取当前元素的个数int size = arrayList.size();// remove(int index); 删除下标为index 的元素arrayList.remove(0);// 判断arrList是否为空, 如果为空就返回true, 否则返回false;arrayList.isEmpty();// set(int index, int element); 将index 下标的元素设置为 elementarrayList.set(0,5);}
}
LInkedList与之类似
ArrayList和Vector
ArrayList和Vector都实现了List接口. 代码演示如图:
import java.util.ArrayList;
import java.util.Vector;public class Main {public static void main(String[] args) {ArrayList<String> arrayList = new ArrayList<>();Vector<String> vector = new Vector<>();// 添加元素arrayList.add("Java");arrayList.add("Python");arrayList.add("C++");vector.add("Java");vector.add("Python");vector.add("C++");// 获取元素System.out.println(arrayList.get(0));System.out.println(vector.get(0));// 删除元素arrayList.remove(0);vector.remove(0);// 获取元素个数System.out.println(arrayList.size());System.out.println(vector.size());}
}
但它们有以下区别:
- 线程安全性:Vector 是线程安全的,而 ArrayList 不是。所以在多线程环境下,应该使用 Vector。
- 性能:由于 Vector 是线程安全的,所以它的性能通常比 ArrayList 差。在单线程环境下,ArrayList 比 Vector 快。
- 初始容量增长方式:当容量不足时,ArrayList 默认会增加 50% 的容量,而 Vector 会将容量翻倍。这意味着在添加元素时,ArrayList 需要更频繁地进行扩容操作,而 Vector 则更适合于存储大量数据。
Vector的grow方法
综上所述,如果不需要考虑线程安全问题,并且需要高效的存取操作,则 ArrayList 是更好的选择;如果需要考虑线程安全以及更好的数据存储能力,则应该选择 Vector。

相关文章:
java面试基础 -- ArrayList 和 LinkedList有什么区别, ArrayList和Vector呢?
目录 基本介绍 有什么不同?? ArrayList的扩容机制 ArrayLIst的基本使用 ArrayList和Vector 基本介绍 还记得我们的java集合框架吗, 我们来复习一下, 如图: 可以看出来 ArrayList和LinkedList 都是具体类, 他们都是接口List的实现类. 但是他们底层的逻辑是不同的, 相信…...
matlab 点云最小二乘拟合空间直线(方法一)
目录 一、算法原理1、空间直线2、最小二乘法拟合二、代码实现三、结果展示四、可视化参考本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、算法原理 1、空间直线 x...
详解junit
目录 1.概述 2.断言 3.常用注解 3.1.Test 3.2.Before 3.3.After 3.4.BeforeClass 3.5.AfterClass 4.异常测试 5.超时测试 6.参数化测试 1.概述 什么是单元测试: 单元测试,是针对最小的功能单元编写测试代码,在JAVA中最小的功能单…...
Nginx的安装及负载均衡搭建
一.Nginx的安装 1)准备安装环境 yum install -y make gcc gcc-c pcre-devel pcre zlib zlib-devel openssl openssl-develPERE PCRE(Perl Compatible Regular Expressions)是一个Perl库,包括 perl 兼容的正则表达式库。 nginx的http模块使用pcre来解…...
JVM学习笔记(一)
1. JVM快速入门 从面试开始: 请谈谈你对JVM 的理解?java8 的虚拟机有什么更新? 什么是OOM ?什么是StackOverflowError?有哪些方法分析? JVM 的常用参数调优你知道哪些? 内存快照抓取和MAT分…...
fastjson 序列化问题:Comparison method violates its general contract
fastjson 序列化问题:Comparison method violates its general contract 问题重现 今天在测试接口的时候,调用了Mybatis Plus 分页查询的接口,然后将查询的结果转换成 Json字符串的形式,结果报了这个错误: java.lang.…...
Angular安全专辑之二——‘unsafe-eval’不是以下内容安全策略中允许的脚本源
一:错误出现 这个错误的意思是,拒绝将字符串评估为 JavaScript,因为‘unsafe-eval’不是以下内容安全策略中允许的脚本源。 二:错误场景 testEval() {const data eval("var sum2 new Function(a, b, return a b); sum2(em…...
十一、Linux用户及用户组的权限信息如何查看?如何修改?什么是权限的数字序号?
目录: 1、认知权限信息 2、rwx? (1)总括: (2)r权限: (3)w权限: (4)x权限: 3、修改权限 (1&a…...
ahooks.js:一款强大的React Hooks库及其API使用教程(二)
一、ahooks.js简介二、ahooks.js安装三、继续ahooks.js API的介绍与使用教程21. useLocalStorageState22. useSessionStorageState23. useClickAway24. usePersistFn25. useCreation26. useFullscreen27. useInViewport28. useInfiniteScroll29. usePagination30. useDynamicLi…...
ARM 配置晶振频率
文章目录 前言串口乱码问题定位内核修改晶振频率uboot 修改晶振频率番外篇 前言 上篇文章《ARM DIY 硬件调试》介绍了 DIY ARM 板的基础硬件焊接,包括电源、SOC、SD 卡座等,板子已经可以跑起来了。 但是发现串口乱码,今天就来解决串口乱码问…...
最强自动化测试框架Playwright(37)-网络
介绍 Playwright 提供 API 来监控和修改浏览器网络流量,包括 HTTP 和 HTTPS。页面执行的任何请求,包括 XHR 和获取请求,都可以被跟踪、修改和处理。 模拟接口 查看我们的 API 模拟指南,了解有关如何 模拟 API 请求,…...
Ant Design Pro 前端脚手架 配置混合导航
Ant Design Pro脚手架 点击查看阅读 混合导航: 顶部导航和侧边栏导航实现联动效果,点击不同的顶部导航按钮会显示对应的子菜单项。 实现点: 1. 路由的配置 菜单展示 我们可以在 route 中进行 menu 相关配置,来决定当前路由是否…...
tcl学习之路(五)(Vivado时序约束)
1.主时钟约束 主时钟通常是FPGA器件外部的板机时钟或FPGA的高速收发器输出数据的同步恢复时钟信号等。下面这句语法大家一定不会陌生。该语句用于对主时钟的名称、周期、占空比以及对应物理引脚进行约束。 create_clock -name <clock_name> -periood <period> -wa…...
Hlang-中英双语言编程语言使用手册
文章目录 介绍Hlang基本使用下载配置环境变量特性中文关键字支持中文符号混合编程中文错误提示终端多行输入基本数据类型整数浮点数列表字符串基本操作变量定义逻辑判断基本运算条件判断循环函数介绍 Hlang是一款基于Python编写的支持中英文混合编程的动态语言。其简单易上手,…...
centos 7 安装docker
系统配置: CentOS关闭selinux sed -i s/SELINUXenforcing/SELINUXdisabled/g /etc/selinux/config关闭防火墙(可选)或者放行相应端口 systemctl stop firewalld.service && systemctl disable firewalld.service配置内核IP 转发 net.ipv4.ip_forward1 dock…...
Spring环境搭建、SpringIOC容器基础、SpringDI基础
文章目录 Spring环境搭建、SpringIOC容器基础、SpringDI基础一、SpringIOC核心思想二、搭建Spring环境步骤三、SpringIOC容器使用步骤四、SpringIOC 总结五、SpringDI(依赖注入)1、基本概念2、实现方式(1)set 注入(2&a…...
CentOS7.9手工配置静态网络流程
进入网卡配置文件 vim /etc/sysconfig/network-scripts/ifcfg-ens33 配置 TYPE"Ethernet" PROXY_METHOD"none" BROWSER_ONLY"no" BOOTPROTO"static" //static 配置静态网络 DEFROUTE"yes" IPV4_FAILURE_FATAL"no…...
JVM面试题-1
1、什么是JVM内存结构? jvm将虚拟机分为5大区域,程序计数器、虚拟机栈、本地方法栈、java堆、方法区; 程序计数器:线程私有的,是一块很小的内存空间,作为当前线程的行号指示器,用于记录当前虚拟…...
漫谈红黑树:红黑树的奇妙演化
漫谈红黑树:红黑树的奇妙演化 一、红黑树的提出二、红黑树性质的简单推导三、结论 博主简介 💡一个热爱分享高性能服务器后台开发知识的博主,目标是通过理论与代码实践的结合,让世界上看似难以掌握的技术变得易于理解与掌握。技能…...
docker启动rabbitmq,但是页面加载不出来问题解决
首先docker启动rabbitmq docker run -d -p 5672:5672 -p 15672:15672 --name rabbitmq rabbitmq -d 后台运行 -p 映射外部端口 -- name 取名(方便管理) 然后发现,成功启动rabbitmq,却加载不进去 因为你下载的是rabbitmq的latest…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...
C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
