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…...
【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
