【Java】ArrayList数组的扩容机制 jdk1.8

  📝个人主页:哈__

期待您的关注 

ArrayList和普通数组不同,ArrayList支持动态扩容,那么ArrayList到底是如何扩容的呢?你又是否知道ArrayList数组的初始长度是多少呢?

在开始介绍之前,我们要先介绍一下ArrayList类中的一些属性。

    /*** *默认初始容量。*/private static final int DEFAULT_CAPACITY = 10;/*** 用于空实例的共享空数组实例。*/private static final Object[] EMPTY_ELEMENTDATA = {};/*** 共享的空数组实例用于默认大小的空实例。我们* 将其与EMPTY_ELEMENTDATA区分开来,以了解何时膨胀多少* 添加第一个元素。*/private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};/*** 存放数组列表元素的数组缓冲区。* 数组列表的容量是这个数组缓冲区的长度。任何空的数组且满足elementData == * DEFAULTCAPACITY_EMPTY_ELEMENTDATA* 将在添加第一个元素时扩展为DEFAULT_CAPACITY。*/transient Object[] elementData; 

elementData就是我们的数据要存储的进入的数组,看上边的注释说,如果数组是空的并且满足elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA的时候,数组就会被扩容为10;

那么接下来我们看一下ArrayList的三个构造方法。

1.有参构造方法

// 传入参数初始化数组的大小
public ArrayList(int initialCapacity) {//如果初始化的大小大于0if (initialCapacity > 0) {//为elementData初始化this.elementData = new Object[initialCapacity];//如果初始化的空间大小为0} else if (initialCapacity == 0) {this.elementData = EMPTY_ELEMENTDATA;} else {throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);}}

2.无参构造方法

public ArrayList() {// elementData数组就等于DEFAULTCAPACITY_EMPTY_ELEMENTDATA数组this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}

3.传入Collention元素列表

/**
*按照指定集合的迭代器返回的顺序,构造一个包含指定集合元素的列表。
**/
public ArrayList(Collection<? extends E> c) {//将元素列表转为数组Object[] a = c.toArray();//如果元素个数不为0if ((size = a.length) != 0) {//如果元素列表是一个ArrayList类型if (c.getClass() == ArrayList.class) {//把a赋给elementDataelementData = a;} else {// 如果不是ArrayList类型,进行元素拷贝elementData = Arrays.copyOf(a, size, Object[].class);}} else {// 如果元素个数为0,将elementData赋值为空数组elementData = EMPTY_ELEMENTDATA;}}

ArrayList的扩容机制

我们向ArrayList中添加数据时,调用的是add()方法。我们跟进查看。首先执行ensureCapacityInternal(size + 1); 这个方法,翻译为确保内部容量,传入的参数是当前集合的元素个数再加上1,一定是加1,这样才能确保正确的添加。我们跟进到方法中查看。

public boolean add(E e) {//确保内部容量 传入当前集合中的元素个数在加上1ensureCapacityInternal(size + 1); elementData[size++] = e;return true;}

这就是这样的一个确保内部容量的方法,传入了一个参数,名为最小的容量,之后调用 ensureExplicitCapacity(calculateCapacity(elementData, minCapacity))这个方法,但是这个方法中还有一个calculateCapacity(elementData, minCapacity)方法,我们先进入这个方法查看

private void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));}

 calculateCapacity方法如下。他需要两个参数,一个是elementData,一个是最小的容量。如果我们的elementDataDEFAULTCAPACITY_EMPTY_ELEMENTDATA这个数组的话,那么我们就返回这个最小的容量和我们内部默认容量中大的一个。如果不是这个默认数组的话直接返回最小容量。这里的判断是因为我们有两种不同的构造函数,一个是无参,另一个是有参,无参构造函数在添加数据的时候会自动将数组扩容为10。

private static int calculateCapacity(Object[] elementData, int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {return Math.max(DEFAULT_CAPACITY, minCapacity);}return minCapacity;}

这样调用完这个函数之后我们就知道数组的容量是多少了。

我们返回ensureExplicitCapacity这个函数接着看。

他需要一个参数就是最小的容量。modCount记录的是数组的修改次数。

接着判断最小的容量减去我们当前数组的容量,如果数组的空间不够,我们就要的调用grow函数进行扩容。否则的话我们就直接回到了最上方的add函数当中进行元素添加。

private void ensureExplicitCapacity(int minCapacity) {modCount++;// overflow-conscious codeif (minCapacity - elementData.length > 0)grow(minCapacity);}

grow函数如下。别慌我写了注释。

private void grow(int minCapacity) {// overflow-conscious code// 这是我们之前数组的容量int oldCapacity = elementData.length;// 新数组的容量应该是旧数组容量+旧数组容量/2,也就是扩容了1.5倍int newCapacity = oldCapacity + (oldCapacity >> 1);// 如果新的容量还是不够,那我们就直接把容量定为传入的最小容量if (newCapacity - minCapacity < 0)newCapacity = minCapacity;// 如果扩容扩出的新数组太大了,比数组最大长度还要大 要重新扩容if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// 将我们的elementData进行扩容,然后赋值给我们的elementData数组,也就是把数组搬到了一个// 大的空间中elementData = Arrays.copyOf(elementData, newCapacity);}

如果真的走到了hugeCapacity函数中,如下所示。

 private static int hugeCapacity(int minCapacity) {// 如果最小的容量小于0 直接报错if (minCapacity < 0) // overflowthrow new OutOfMemoryError();// 如果最小容量比数组最大容量大,返回整形的最大值,否则的话就是等于数组最大值// 不再扩充1.5倍了return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;}

到了这一步真的就是走完了最最最上方的ensureCapacityInternal方法,然后就可以添加元素了。

以上内容就是ArrayList集合的扩容机制。

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

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

相关文章

【Python】如何安装Python

推荐安装python39版本 1.安装python1.1.在任意盘新建Python39目录1.2.双击安装包1.3.安装成功后&#xff0c;WINRcmd进入dos页面&#xff0c;输入 python&#xff0c;即可查看是否安装成功 2.环境变量配置2.1.打开 我的电脑-》高级系统设置-》环境变量-》系统变量2.2.如上图配置…

MHA高可用集群部署

一、MHA的概念 1.1 MHA概述 一套优秀的MySQL高可用环境下故障切换和主从复制的软件MHA的出现就是解决MySQL 单点的问题。 MySQL故障过程中&#xff0c;MHA能做到0-30秒内自动完成故障切换MHA能在故障切换的过程中最大程度上保证数据的一致性以达到真正意义上的高可用 …

​如何用“Dreamina”进行文生图​

文生图&#xff0c;顾名思义&#xff0c;就是用文字描述来生成图片。近年来&#xff0c;随着人工智能技术的进步&#xff0c;文生图技术也逐渐成熟&#xff0c;并逐渐应用于各种领域&#xff0c;例如设计、创作、娱乐等等。 本文将介绍如何使用“Dreamina”进行文生图。 步骤…

2024.3.25-26记:二叉树的遍历

二叉树的遍历深度优先遍历(DFS)递归遍历前序递归遍历&#xff1a;中序递归遍历后续递归遍历 非递归遍历前序非递归遍历中序非递归遍历后续非递归遍历 宽度优先遍历&#xff08;BFS): 二叉树的遍历 二叉树遍历大体上分为深度优先遍历&#xff08;DFS)和宽度优先遍历(BFS)&#…

Linux 常用命令(1)

&#x1f607;作者介绍&#xff1a;一个有梦想、有理想、有目标的&#xff0c;且渴望能够学有所成的追梦人。 &#x1f386;学习格言&#xff1a;不读书的人,思想就会停止。——狄德罗 ⛪️个人主页&#xff1a;进入博主主页 &#x1f5fc;专栏系列&#xff1a;Linux 随笔集合 …

必应bing国内广告推广怎么做,烧不烧钱?

必应Bing作为全球领先的搜索引擎之一&#xff0c;其国内广告平台提供了丰富而精准的广告资源&#xff0c;为众多企业带来极具性价比的品牌推广机会。然而&#xff0c;要想在必应Bing上取得理想的广告效果&#xff0c;并不一定意味着“烧钱”&#xff0c;而是需要通过科学的策略…

Spring日志框架

前言 本文我们简单说说关于Spring中的日志框架,以及对应的注解 我们知道,公司服务器在运行的时候,一定会打印日志,有很多优点,比如预防报警,或者是某重大事故尝试修复等等都需要查看日志 应该说日志对我们来说并不陌生,我们在之前刷题或者是程序遇到bug的时候也经常会将程序的状…

Databricks 开源 DBRX:一款功能强大的新型企业级语言模型

Databricks 公司发布了 DBRX&#xff0c;这是一款性能优异的大语言模型&#xff0c;在各项测试中均超越了现有的开源模型。DBRX 的目标是为企业提供高质量、可定制的 AI 工具&#xff0c;帮助企业更好地利用生成式 AI 技术。 DBRX 的一大亮点是其出色的性能。在语言理解、编程…

Redis 主从复制原理,设计的真巧妙!

前言 今天继续来看看有关 Redis 的一个问题&#xff0c;主从复制。通常&#xff0c;对于大多数的场景来说&#xff0c;读比写更多&#xff0c;于是对于缓存的水平扩展&#xff0c;其中的一个方式 “主从复制” 就是一个常见的思路。有了主从复制&#xff0c;那么可以扩展出很多…

Kibana操作Elasticsearch教程

文章目录 简介ES文档操作创建索引查看索引创建映射字段查看映射关系字段属性详解typeindexstore 字段映射设置流程 新增数据新增会随机生成id新增自定义id智能判断 修改数据删除数据查询基本查询查询所有&#xff08;match_all&#xff09;匹配查询多字段查询词条匹配多词条精确…

大模型预测,下一个token何必是文字?

太快了太快了… 大模型的生成技能&#xff0c;已经到了普通人看不懂的境界&#xff01; 它可以根据用户过去5年的体检报告&#xff0c;生成未来第1年、第2年、第3年的体检报告。 你看&#xff0c;这个生成的过程&#xff0c;是不是像极了ChatGPT&#xff0c;根据历史单词预测…

测开——测试用例设计题

1.测试手机的短信功能需要考虑哪些测试点&#xff1f; 考测试思维 是否能正常打开或进入短信界面短信可以正常编辑、修改、删除短信可以正常发送、接收短信页面的字体、颜色显示是否正常【UI界面 手机设置了字体颜色 大小是否同步】短信的字体是否能够调整同时给多个人发短信…

工业测试测量仪器与人工智能(AI)如何结合

工业测试测量仪器与人工智能&#xff08;AI&#xff09;的结合可以通过多种方式实现&#xff0c;其中一些主要方法包括&#xff1a; 1. 数据分析和预测 智能数据分析&#xff1a;利用AI算法对从传感器和测试仪器收集的数据进行分析&#xff0c;识别模式、趋势和异常&#xff0…

vue+elementUI搭建动态表头的表格

前提&#xff1a;以下代码是vue2项目结合elementUi完成的 数据结构 后端传来的数据是两个list&#xff0c;一个表头的list&#xff0c;一个表格内容的list // 表头 headTableAtts: [{ columnLabel: 姓名, columnName: name },{ columnLabel: 年龄, columnName: age },{ colu…

ensp中pc机访问不同网络的服务器

拓扑图如下&#xff0c;资源已上传 说明&#xff1a;pc通过2个路由访问server服务器 三条线路分别是192.168.1.0网段&#xff0c;192.168.2.0网段和192.168.3.0网段&#xff0c;在未配置的情况下&#xff0c;pc设备是访问不到server的 具体操作流程 第一&#xff1b;pc设备…

简单了解原型模式

什么是原型模式 区别于单例模式&#xff0c;原型模式的一个类可以有多个实例化的对象。 原型模式通过拷贝来产生新的对象&#xff0c;而不是new&#xff0c;并且可以根据自己的需求修改对象的属性。 实现Cloneable接口实现拷贝 而拷贝又分为浅拷贝和深拷贝&#xff0c;两者在…

python的神奇bug2

今天测试出一个很诡异的bug&#xff0c; 这个错误还真的很难发现 测试1 a [1,10,100] for i in a:print(i)if(i10):a[20,30,-1]一般来说我们在进行迭代时&#xff0c;a这个值时不能改动的&#xff0c;但是现在的问题时如果我不小心给改动了呢&#xff0c;结果如下 也就是说…

【数据结构刷题专题】—— 二分查找

二分查找 二分查找模板题&#xff1a;704. 二分查找 二分查找前提&#xff1a; 有序数组数组中无重复元素 左闭右闭&#xff1a; class Solution { public:int search(vector<int>& nums, int target) {int left 0;int right nums.size() - 1;while (left <…

基于unbantu的nginx的配置

目录 前言: 1.安装nginx并进行测试 1.1使用nginx -v 命令查看版本 1.2开启服务 查看端口 1.3测试 2.nginx的静态资源访问配置 2.1创建静态资源存放的目录 2.2写入目录中测试文件对应的内容 2.3修改配置文件 2.4 测试 3.虚拟主机配置 3.1创建目录 3.2写入测试…

SOLIDWORKS 2024 推荐硬件:开箱即用的配置以及升级优化的SOLIDWORKS硬件

SOLIDWORKS 2024已于2023年年末发布&#xff0c;使用SOLIDWORKS 2024的用户关注的问题之一就是&#xff1a;适合SOLIDWORKS2024这个版本的最佳硬件是什么&#xff1f; 这篇文章&#xff0c;硕迪科技将推荐SOLIDWORKS 2024的开箱即用的解决方案以及各个硬件的配置要求。 这些建议…