Java ArrayList解密

        数组的大小是固定的,一旦创建的时候指定了大小,就不能再调整了。也就是说,如果数组满了,就不能再添加任何元素了。

        ArrayList 在数组的基础上实现了自动扩容,并且提供了比数组更丰富的预定义方法(各种增删改查),非常灵活。

        下面我们就来探究一下ArrayList的各个方法的实践和原理,以及算法复杂度

一、创建ArrayList

        创建方式:

ArrayList<String> alist = new ArrayList<String>();

        看看ArrayList的构造函数:

        如果初始化大小的话,会构造一个这样长度的object数组;如果初始化为0或者不填的话,就会创建一个空数组。

        也可以看出,如果非常确定 ArrayList 中元素的个数,在创建的时候还可以指定初始大小,可以有效地避免在添加新的元素时进行不必要的扩容。

二、添加元素 

alist.add("xxx");

        可以看出来,add过程分为两步,第一步确保数组的大小足够,第二步将元素添加到末尾

2.1 calculateCapacity

        进去看 ensureCapacityInternal,源码如下:

        那么首先先看 calculateCapacity,这个函数是为了确定数组的大小。

        如果数组是空的,那大小就是max {当前size+1,默认大小},源码中默认大小是10;如果数组不为空,那就返回他的指定大小

  

2.2 ensureCapacityInternal

        确保数组的大小足够。如果数组要溢出了,就要调用grow方法扩容 

 

2.3 grow

     // 检查是否会导致溢出,oldCapacity 为当前数组长度int oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1); // 扩容至原来的1.5倍if (newCapacity - minCapacity < 0) // 如果还是小于指定容量的最小值newCapacity = minCapacity; // 直接扩容至指定容量的最小值if (newCapacity - MAX_ARRAY_SIZE > 0) // 如果超出了数组的最大长度newCapacity = hugeCapacity(minCapacity); // 扩容至数组的最大长度// 将当前数组复制到一个新数组中,长度为 newCapacityelementData = Arrays.copyOf(elementData, newCapacity);

2.4 总结

堆栈过程图示:
add(element)
└── if (size == elementData.length) // 判断是否需要扩容├── grow(minCapacity) // 扩容│   └── newCapacity = oldCapacity + (oldCapacity >> 1) // 计算新的数组容量│   └── Arrays.copyOf(elementData, newCapacity) // 创建新的数组├── elementData[size++] = element; // 添加新元素└── return true; // 添加成功

三,向指定位置添加元素

alist.add(0, "");

        上面讲清楚 ensureCapacityInternal之后,这里就很容易理解了。

public void add(int index, E element) {rangeCheckForAdd(index); // 检查索引是否越界ensureCapacityInternal(size + 1);  // 确保容量足够,如果需要扩容就扩容System.arraycopy(elementData, index, elementData, index + 1,size - index); // 将 index 及其后面的元素向后移动一位elementData[index] = element; // 将元素插入到指定位置size++; // 元素个数加一
}

3.1  rangeCheckForAdd

        判断索引是否越界,越界了就抛错 

3.2  ensureCapacityInternal

        上面已经讲过,不多赘述。

四、更新元素

alist.set(0, "");

 

public E set(int index, E element) {rangeCheck(index); // 检查索引是否越界E oldValue = elementData(index); // 获取原来在指定位置上的元素elementData[index] = element; // 将新元素替换到指定位置上return oldValue; // 返回原来在指定位置上的元素
}

4.1 elementData

        获取索引位置数组 

五、删除指定位置元素 

public E remove(int index) {rangeCheck(index); // 检查索引是否越界modCount++;    //集合实际被修改的次数+1,这个是ArrayList的一个成员变量E oldValue = elementData(index); // 获取要删除的元素int numMoved = size - index - 1; // 计算需要移动的元素个数if (numMoved > 0) // 如果需要移动元素,就用 System.arraycopy 方法实现System.arraycopy(elementData, index+1, elementData, index,numMoved);elementData[--size] = null; // 将数组末尾的元素置为 null,让 GC 回收该元素占用的空间return oldValue; // 返回被删除的元素
}

六、删除指定元素 

list.remove("");

        分为元素为null和不为null的情况,区别在于,为null的时候用==判断,不为null的时候用equals判断,逻辑上并没有什么区别。

        如果找到元素,用fashRemove方法删除元素,返回true;找不到元素就返回false。 

 

6.1 fastRemove 

private void fastRemove(int index) {int numMoved = size - index - 1; // 计算需要移动的元素个数if (numMoved > 0) // 如果需要移动元素,就用 System.arraycopy 方法实现System.arraycopy(elementData, index+1, elementData, index,numMoved);elementData[--size] = null; // 将数组末尾的元素置为 null,让 GC 回收该元素占用的空间
}

七、查找元素 

list.indexOf("");
list.lastIndexOf("");

        如果要正序查找一个元素,可以使用 indexOf() 方法;如果要倒序查找一个元素,可以使用 lastIndexOf() 方法。

lastIndexOf() 方法和 indexOf() 方法类似,不过遍历的时候从最后开始。 

八、各个方法时间复杂度 

  • get        O(1)
  • add       最好O(1),在末尾插入;最坏O(n),插入后移动数组
  • remove 最好O(1),在末尾删除;最坏O(n),删除后移动数组
  • set        O(1)

 参考:

深入探讨 Java ArrayList:从源码分析到实践应用 | 二哥的Java进阶之路

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

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

相关文章

pillow像型学操作(转载笔记) --- 西北乱跑娃

Opencv、Matplotlib(plt)、Pillow(PIL)、Pytorch读取数据的通道顺序 需注意:Pillow加载图像后的尺寸是二维,图形化是三维,但无法打印三维尺寸。 详细区别: Opencv:uint8的ndarray数据,通道顺序[h, w, c],颜色通道BGR。 导入模块:import cv2 (1)cv2.imread() (2)cv…

论文阅读: AAAI 2022行人重识别方向论文-PFD_Net

本篇博客用于记录一篇行人重识别方向的论文所提出的优化方法《Pose-Guided Feature Disentangling for Occluded Person Re-identification Based on Transformer》&#xff0c;论文中提出的PDF_Net模型的backbone是采用《TransReID: Transformer-based Object Re-Identificati…

探寻最短路径之谜:Dijkstra算法详解

探寻最短路径之谜&#xff1a;Dijkstra算法详解 大家好&#xff0c;我是免费搭建查券返利机器人赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天&#xff0c;让我们一起深入研究一项在图论领域中备受推崇的算法…

YHZ014 Python 算术运算符

&#x1f989; 运算符 资源编号&#xff1a;YHZ014 配套视频&#xff1a;https://www.bilibili.com/video/BV1zy4y1Z7nk?p15 &#x1f578;️ 算术运算符 以下假设变量 a10&#xff0c;变量 b21&#xff1a; 运算符描述实例加 - 两个对象相加a b 输出结果 31-减 - 得到负数…

【AI】人工智能爆发推进器之迁移学习

目录 一、什么是迁移学习 二、迁移学习和VAE 三、迁移学习的分类 3.1 按迁移内容分类&#xff1a; 3.2 按迁移方法分类&#xff1a; 3.3 按学习形式分类&#xff1a; 3.4 按目标域有无标签分类&#xff1a; 3.5 按学习方法分类&#xff1a; 3.6 按特征分类&#xff1a…

vue常见属性

vue实例的属性 data 用于设置和绑定的字段 data() {return{plan: ,planlist: []} },methods 用来设置方法&#xff0c;绑定对应的按钮或者事件 <button v-on:click“addPlan”>添加任务 methods: {addPlan() {if(this.plan null || this.plan ){return}this.planlist.…

TypeScript 之 interface 和 type 的区别

结论&#xff1a; 1、可以声明的数据类型 type 可以修饰任何类型 &#xff08;值类型和引用数据类型&#xff09; interface 只能修饰引用类型 &#xff08;对象、数组、函数&#xff09; //interface 声明对象属性 interface ins {a: string;b?: number; //可选项 }// int…

HackTheBox - Medium - Linux - Encoding

Encoding 前言 经过10个月左右的网安自学&#xff0c;我想说的第一句话无疑是&#xff1a;感谢TryHackMe。当然&#xff0c;后续的HackTheBox&学院、CRTO等等&#xff0c;对我的帮助都很大。 许多师傅们都在年度总结&#xff0c;我也看了大家都收获很多&#xff0c;都很…

Docker容器基础知识点总结

一 、Docker架构 dockers加速镜像&#xff1a; sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-EOF {"registry-mirrors": ["https://z90yxq2m.mirror.aliyuncs.com"] } EOF sudo systemctl daemon-reload sudo systemctl restar…

MySQL基础学习: linux系统mysql 密码插件 validate_password安装

1、没有安装mysql密码插件&#xff0c;执行命令&#xff1a;SHOW VARIABLES LIKE ‘validate_password%’; 2、安装mysql密码插件&#xff0c;执行命令&#xff1a;install plugin validate_password soname ‘validate_password.so’; 3、再次执行&#xff1a;SHOW VARIABLE…

【Unity入门】MenuItem 和 ContextMenu 的使用方法

目录 一、ContextMenu描述使用示例ContextMenuItem使用示例 二、MenuItem描述使用示例 三、MenuItem 和 ContextMenu 的区别 一、ContextMenu 描述 ContextMenu 属性用于向上下文菜单添加命令。 在该附加脚本的 Inspector 中&#xff0c;当用户选择该上下文菜单时&#xff0c…

计算机网络技术--念念

选择题&#xff1a; 1.只要遵循GNU通用公共许可证,任何人和机构都可以自由修改和再发布的操作系统是&#xff08;Linux &#xff09; 2.在计算机网络的各种功能中,最基本的、为其他功能提供实现基础的是&#xff08;实现数据通信 &#xff09; 3.计算机网络具有分布式处理功能,…

slice,splice的区别和使用

一、slice slice(开始&#xff0c;结束) 第一个参数是开始的位置&#xff0c;第二个参数是结束的位置&#xff0c;他并不会改变原数组 let arrOne [22,33,44,55,66]; let arrTwo arrOne.slice(1,3);//参数是根据数组的下标来截取的 console.log(arrTwo); //[33,44] consol…

【Spring实战】16 Profile

文章目录 1. 定义2. 使用2.1 定义 Profile2.2 激活 Profile 3. 演示3.1 properties文件3.2 打印日志3.3 启动服务&验证3.4 修改 active3.5 重启服务&验证 4. 应用场景4.1 数据库配置4.2 日志配置 5. 代码详细总结 Spring 框架提供了一种强大的机制&#xff0c;允许在不…

Linux:20个linux常用命令

20个linux常用命令 1. ls&#xff1a;列出文件list 2. cd&#xff1a;切换目录change directory 3. cp&#xff1a;复制copy 4. mv&#xff1a;移动move 5. rm&#xff1a;移除&#xff0c;删除remove 6. mkdir&#xff1a;创建文件夹make directory 7. rmdir&#xff1a;移除&…

docker 在线安装mysql 8.0.21版本

1、拉取mysql 8.0.21版本镜像 2、查看镜像 docker images 3、在宿主机 /usr/local/mysql 下的 conf 文件夹下&#xff0c;创建 my.cnf 文件&#xff0c;并编辑内容 [mysql] default-character-setutf8 [client] port3306 default-character-setutf8 [mysqld] port3306 se…

Omnifocus - Reference Manual for V4 - 1

1, Welcome to OmniFocus OmniFocus 4 以你的任务大纲为中心&#xff0c;为你所有的 Apple 设备带来一致的体验&#xff0c;并针对每种设备类型进行了优化。 Centered around your task outline, OmniFocus 4 brings a consistent experience, optimized for each device type,…

JavaScript 关键特性

生活中&#xff0c;条件与我们息息相关。举几个例子&#xff1a;如果这周放假&#xff0c;那么我就要出去玩&#xff1b;如果明天不下雨&#xff0c;我就和小花出去踢足球&#xff1b;如果我饿了&#xff0c;我要么吃饭&#xff0c;要么吃面&#xff0c;要么就忍着。同样的&…

普中STM32-PZ6806L 使用FlyMcu串口烧录程序

简介 我的串口下载电路坏掉了, 所以研究了下如何通过USB转TTL进行程序的下载, 为后续Bootloader部分做准备;连接 我的板几乎是十年前买的&#xff0c; 所以电路与现有网上的资料有些差异, 所以仅供参考 USB 转 TTL线 与开发板 连接&#xff0c; 如图图中 ①, 需要去掉第一个…

YOLOv8训练损失、mAP画图功能 | 支持多结果对比,多结果绘在一个图片(科研必备)

一、本文介绍 本文给大家带来的是YOLOv8系列的绘图功能&#xff0c;我将向大家介绍YOLO系列的绘图功能。我们在进行实验时&#xff0c;经常需要比较多个结果&#xff0c;针对这一问题&#xff0c;我写了点代码来解决这个问题&#xff0c;它可以根据训练结果绘制损失(loss)和mA…