java中的集合之List

Java 中的 List 是一个接口,定义了一组有序的元素集合,允许重复元素。List 接口有多个实现形式,主要包括:

  1. ArrayList: 基于动态数组实现,支持快速随机访问,适用于需要频繁读取数据的场景。
  2. LinkedList: 基于双向链表实现,支持高效的插入和删除操作,适合需要频繁插入和删除的场景。
  3. Vector: 基于动态数组实现,但线程安全,性能较 ArrayList 低,现代开发中不推荐使用。
  4. Stack: 继承自 Vector,实现了栈的功能(后进先出)。
  5. CopyOnWriteArrayList: 线程安全的 ArrayList 实现,通过在写操作时复制数组,适合读操作远多于写操作的场景。

每种实现都有其特定的特点和适用场景,可以根据具体需求选择使用。这里主要学习平时最常用的ArrayList

ArrayList

ArrayList 的底层数据结构是动态数组,具有快速的随机访问和动态扩容能力。虽然在增加和删除元素时可能会有性能开销,但其访问操作具有 O(1) 的时间复杂度。

内部几个属性

private int size;
transient Object[] elementData; 
private static final int DEFAULT_CAPACITY = 10;
  • elementData 是存储元素的底层数组。
  • size 记录当前 ArrayList 中的元素个数。
  • DEFAULT_CAPACITY默认容量大小。

ArrayList默认无参构造函数,elementData 是个空数组,int参数可以指定elementData 初始化大小。

    public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}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);}}
插入操作

添加元素时,如果数组有足够的空间,就直接插入到数组的末尾。如果没有足够的空间,就触发扩容操作。

    public boolean add(E e) {//检查扩容ensureCapacityInternal(size + 1);  // Increments modCount!!//插入元素elementData[size++] = e;return true;}
扩容机制
  1. 容量检查:每当 ArrayList 需要添加新元素时,会先检查当前容量是否足够。如果需要的容量超过当前数组容量,则会触发扩容。

  2. 计算新容量:扩容时会计算一个新的容量,通常是将当前容量增加一半。具体来说,ArrayList 在 Java 标准库中的实现中,通常将容量增加 50%(即扩容为原容量的 1.5 倍),以提供足够的余地而不会频繁触发扩容。

  3. 创建新数组:创建一个更大的数组来容纳更多的元素。新数组的大小是根据计算结果确定的。

  4. 复制元素:将原数组中的元素复制到新的数组中。此操作的时间复杂度是 O(n),其中 n 是原数组的长度。

  5. 更新引用:将 ArrayList 的内部数组引用更新为新的数组。

    扩容操作在ensureCapacityInternal()方法内完成。

   // minCapacity入参值是 size+1 private void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));}//计算容量private static int calculateCapacity(Object[] elementData, int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//当前list是空,创建时未设置容量//返回默认容量(10)和新增后实际容量的最大值return Math.max(DEFAULT_CAPACITY , minCapacity);}return minCapacity;}
//确认是否扩容private void ensureExplicitCapacity(int minCapacity) {modCount++;// overflow-conscious code//计算操作后的容量大于当前可变数组的大小,存不下了。if (minCapacity - elementData.length > 0)grow(minCapacity);}

按照上面的逻辑,如果使用默认无参构造函数创建list,第一次执行add方法,计算容量会返回默认容量10,然后在创建一个10长度的数组,也就是第一次add时候才创建数组。

来看具体的grow方法

    private void grow(int minCapacity) {// 旧容量int oldCapacity = elementData.length;//新容量 = 旧容量 + 旧容量右移位1(相当于除以2) 这也就是扩容1.5的来源int newCapacity = oldCapacity + (oldCapacity >> 1);//再次判断新容量是否小于需要的最小容量,这里第一次添加的时候会走这里,因为旧容量=0,计算出新容量还是0if (newCapacity - minCapacity < 0)newCapacity = minCapacity;/**判断是否超过最大容量,MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8,一般走不到这里,这么大容量使用场景不合适,可能已经内存溢出了*/if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// minCapacity is usually close to size, so this is a win://使用Arrays.copyOf扩容至新容量elementData = Arrays.copyOf(elementData, newCapacity);}
元素删除

删除操作步骤:

  1. 找到要删除的元素的位置:根据索引或对象。
  2. 调整数组:如果删除的不是最后一个元素,需要将后续元素向前移动。
  3. 更新 size:减少列表的大小。
  4. 释放引用:将被移除的元素位置设为 null 以帮助垃圾回收。
    public E remove(int index) {rangeCheck(index);modCount++;E oldValue = elementData(index);//需要移动的元素数量,从被删除元素往后的所有元素int numMoved = size - index - 1;if (numMoved > 0)//复制移动数组System.arraycopy(elementData, index+1, elementData, index,numMoved);elementData[--size] = null; // clear to let GC do its workreturn oldValue;}

System.arraycopy(Object src, int srcPos,Object dest, int destPos, int length);4个参数的意思:

  • src: 源数组,从中复制元素。
  • srcPos: 源数组中的起始位置(起始索引),从该位置开始复制元素。
  • dest: 目标数组,将元素复制到该数组中。
  • destPos: 目标数组中的起始位置(起始索引),从该位置开始写入元素。
  • length: 复制的元素数量。
Arrays.asList操作

Arrays.asList 将数组转换为一个固定大小的 List。使用的时候要特别注意,返回的 List 不能改变大小,但可以修改元素。因为返回的实例是Arrays对应的一个内部类ArrayList,不是java.util.ArrayList。这个内部类ArrayList中存储数据的数组是final类型的,虽然继承自AbstractList,但是add()和remove()方法没有实现,添加或删除操作会抛出UnsupportedOperationException异常。

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

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

相关文章

宝塔部署python项目

宝塔部署-python项目文章浏览阅读559次&#xff0c;点赞11次&#xff0c;收藏9次。在添加项目后&#xff0c;选择项目所在的路径&#xff0c;然后命令行启动主py文件。具体先看项目日志&#xff0c;根据日志在环境管理处下载包。首先下载项目需要的python版本。_宝塔部署python…

LabVIEW提高开发效率技巧----VI服务器和动态调用

VI服务器&#xff08;VI Server&#xff09;和动态调用是LabVIEW中的两个重要功能&#xff0c;可以有效提升程序的灵活性、模块化和可扩展性。通过这两者的结合&#xff0c;开发者可以在运行时动态加载和调用VI&#xff08;虚拟仪器&#xff09;&#xff0c;实现更为复杂的应用…

C++和OpenGL实现3D游戏编程【目录】

欢迎来到zhooyu的专栏。 个人主页&#xff1a;【zhooyu】 文章专栏&#xff1a;【OpenGL实现3D游戏编程】 贝塞尔曲面演示&#xff1a; 贝塞尔曲面演示zhooyu 本专栏内容&#xff1a; 我们从游戏的角度出发&#xff0c;用C去了解一下游戏中的功能都是怎么实现的。这一切还是要…

基于yolov8的无人机检测系统python源码+onnx模型+评估指标曲线+精美GUI界面

【算法介绍】 基于YOLOv8的无人机检测系统是一项前沿技术&#xff0c;结合了YOLOv8深度学习模型的强大目标检测能力与无人机的灵活性。YOLOv8作为YOLO系列的最新版本&#xff0c;在检测精度和速度上均有显著提升&#xff0c;特别适用于复杂和高动态的场景。 该系统通过捕获实…

论文笔记:基于LLM和多轮学习的漫画零样本角色识别与说话人预测

整理了ACM MM2024 Zero-Shot Character Identification and Speaker Prediction in Comics via Iterative Multimodal Fusion&#xff09;论文的阅读笔记 背景模型框架实现细节 实验数据集实验可视化消融实验 背景 最近读到一篇新文章&#xff0c;主要是做漫画中的零样本角色识…

pikachu下

CSRF(跨站请求伪造) CSRF(get) url变成了这样了&#xff0c;我们就可以新开个页面直接拿url去修改密码 http://pikachu-master/vul/csrf/csrfget/csrf_get_login.php?username1&password2&submitLogin CSRF(post&#xff09; 这里只是请求的方式不同&#xff0c;…

HC-SR04超声波传感器详解(STM32)

目录 一、介绍 二、传感器原理 1.原理图 2.引脚描述 3.工作原理介绍 三、程序设计 main.c文件 ultrasonic.h文件 ultrasonic.c文件 四、实验效果 五、资料获取 项目分享 一、介绍 HC-SR04超声波传感器是通过发送和接收超声波&#xff0c;利用时间差和声音传播速度…

带你深入了解C语言指针(四)

目录 前言一、回调函数是什么&#xff1f;二、qsort使用1.什么是qsort2.qsort函数的语法解析3.回顾冒泡排序4.使用qsort函数排序整型数据4.1 思路分析4.2 完整代码&#xff1a;4.3 总体逻辑展现 5.使用qsort函数排序结构数据5.1 strcmp( )函数5.2 思路分析5.2.1 按名字比较5.2.…

力扣每日一题 公交站间的距离

环形公交路线上有 n 个站&#xff0c;按次序从 0 到 n - 1 进行编号。我们已知每一对相邻公交站之间的距离&#xff0c;distance[i] 表示编号为 i 的车站和编号为 (i 1) % n 的车站之间的距离。 环线上的公交车都可以按顺时针和逆时针的方向行驶。 返回乘客从出发点 start 到目…

C# 使用Socket通信,新建WinForm服务端、客户端程序

一、新建WinForm Socket服务端程序 注&#xff1a;rtbReceviceMsg为RichTextBox控件 服务端程序、界面 服务端代码 public partial class Form1 : Form {public Form1(){InitializeComponent();}public virtual void TriggerOnUpdateUI(string message){if (this.InvokeRequir…

Oracle发送邮件功能:配置自动化发信指南?

Oracle发送邮件服务设置方法&#xff1f;怎么用Oracle数据库发信&#xff1f; Oracle数据库作为企业级应用的核心&#xff0c;其内置的发送邮件功能为企业提供了强大的自动化工具。AokSend将详细介绍如何配置Oracle发送邮件功能&#xff0c;以实现自动化发信&#xff0c;从而提…

leetcode 2576.求出最多标记下标

2576.求出最多标记下标 题意&#xff1a; 解析&#xff1a; 数组长为 n n n&#xff0c;因为一次标记两个&#xff0c;所以数组中最多有 ⌊ n 2 ⌋ \lfloor \frac{n}{2}\rfloor ⌊2n​⌋ 对标记。 贪心的考虑&#xff0c;一个数 x 一定优先与满足 y ≥ 2 x y \ge 2x y≥2…

上海泗博EtherNet/IP转PROFIBUS DP网关EPS-320IP成都地铁项目应用案例

背景&#xff1a; 地铁&#xff0c;作为城市的活力脉搏&#xff0c;不仅是衔接城市生活的关键纽带&#xff0c;更是现代城市交通体系中不可或缺的核心组成部分。因此&#xff0c;确保地铁的稳定运行对任何一座城市都至关重要。 上海泗博自动化&#xff0c;作为与成都地铁项目合…

使用ENVI之辐射定标

将下载好的遥感影像导入遥感影像处理软件ENVI 5.6中 使用ENVI 5.6的Toolbox中的Radiometric Calibration工具 跳出的Date Input File界面中选中要进行辐射定标的文件选中 再在跳出的Radiometric Calibration界面中将Output Interleave改为BIL再点击Apply FLAASH Settings Soale…

【iOS】push和present的区别

【iOS】push和present的区别 文章目录 【iOS】push和present的区别前言pushpop presentdismiss简单小demo来展示dismiss和presentdismiss多级 push和present的区别区别相同点 前言 在iOS开发中&#xff0c;我们经常性的会用到界面的一个切换的问题&#xff0c;这里我们需要理清…

网络(四)——HTTP协议

文章目录 认识urlurlencode和urldecodeHTTP协议格式HTTP的方法HTTP的状态码HTTP常见Header 虽然应用层的协议是由人为规定的&#xff0c;但是已经有大佬们定义了一些现成的&#xff0c;又非常好用的应用层协议&#xff0c;供我们直接参考使用. HTTP(超文本传输协议)就是其中之一…

适合骑行的开放式耳机哪个品牌好?四款开放式蓝牙耳机推荐

骑行时是否有必要佩戴耳机是一个需要权衡安全与便利的问题。因为虽然耳机能提供音乐、导航等功能&#xff0c;但也可能分散注意力&#xff0c;影响骑行安全。而且这也是需要看个人需求决定的&#xff0c;骑行戴耳机的需求是什么&#xff0c;我想大部分人应该就是为了接听电话&a…

[数据集][目标检测]无人机识别检测数据集VOC+YOLO格式6986张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;6986 标注数量(xml文件个数)&#xff1a;6986 标注数量(txt文件个数)&#xff1a;6986 标注…

MySQL —— 视图

概念 视图是一张虚拟的表&#xff0c;它是基于一个或多个基本表或其他视图的查询结果集。 视图本身不存储数据&#xff0c;而是通过执行查询来动态生成数据&#xff0c;用户可以像操作普通表一样使用视图来进行查询更新与管理等操作。 视图本身也不占用物理存储空间&#xf…

Redis基础数据结构之 Sorted Set 有序集合 源码解读

目录标题 Sorted Set 是什么?Sorted Set 数据结构跳表&#xff08;skiplist&#xff09;跳表节点的结构定义跳表的定义跳表节点查询层数设置 Sorted Set 基本操作 Sorted Set 是什么? 有序集合&#xff08;Sorted Set&#xff09;是 Redis 中一种重要的数据类型&#xff0c;…