【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://www.mzph.cn/news/779120.shtml

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

相关文章

Qt常用容器之:QVector

参考原文&#xff1a;https://www.cnblogs.com/ybqjymy/p/17996789 在计算机编程的世界中&#xff0c;数据结构是一个核心概念&#xff0c;它为我们提供了有效地组织和存储数据的方法。在众多数据结构中&#xff0c;向量&#xff08;Vector&#xff09;作为一种动态数组&#…

HarmonyOS实战开发-使用List组件实现导航与内容联动的效果。

1 卡片介绍 使用ArkTS语言&#xff0c;实现一个导航与内容二级联动的效果。 2 标题 二级联动&#xff08;ArkTS&#xff09; 3 介绍 本篇Codelab是主要介绍了如何基于List组件实现一个导航和内容的二级联动效果。样例主要包含以下功能&#xff1a; 切换左侧导航&#xff…

鸿蒙OS开发实战:【打造自己的搜索入口】

背景 几乎每家应用中都带有搜索功能&#xff0c;关于这个功能的页面不是特别复杂&#xff0c;但如果要追究其背后的一系列逻辑&#xff0c;可能是整个应用中最复杂的一个功能。今天主要实践目标&#xff0c;会抛开复杂的逻辑&#xff0c;尝试纯粹实现一个“搜索主页”&#xf…

初识Node.js与内置模块

能够知道什么是 Node.js能够知道 Node.js 可以做什么能够说出 Node.js 中的 JavaScript 的组成部分能够使用 fs 模块读写操作文件能够使用 path 模块处理路径能够使用 http 模块写一个基本的 web 服务器 一.初识Node.js 1.浏览器中的 JavaScript 的组成部分 2.Node.js 简介 …

MySQL创建表:练习题

练习题&#xff1a; 创建一个名为"students"的数据库&#xff0c;并切换到该数据库。 在"students"数据库中创建一个名为"grades"的表&#xff0c;包含以下字段&#xff1a; id: 整数类型 name: 字符串类型&#xff0c;学生姓名 subject: 字符串…

postgis已有表插入外部表数据带空间字段和主键

1、postgis已有表 其中gid是主键字段,geom是几何字段 2、待插入表的数据(分三种情况) (1)通过坐标将写入几何类型字段 INSERT INTO test (gid, geom, mc,lng,lat) SELECT (SELECT COALESCE(MAX(gid)<

力扣练习3.28

138. 随机链表的复制 浅拷贝和深拷贝&#xff1a; 前者新建一个数据结构&#xff0c;不创建元素副本&#xff1b; 后者不仅新建一个数据结构&#xff0c;而且新建一个数据副本。 深拷贝&#xff08;Deep Copy&#xff09;和浅拷贝&#xff08;Shallow Copy&#xff09;是在复制…

微服务demo(二)nacos服务注册与集中配置

环境&#xff1a;nacos1.3.0 一、服务注册 1、pom&#xff1a; 移步spring官网https://spring.io&#xff0c;查看集成Nacos所需依赖 找到对应版本点击进入查看集成说明 然后再里面找到集成配置样例&#xff0c;这里只截一张&#xff0c;其他集成内容继续向下找 我的&#x…

There is no getter for property named ‘deleted‘

实体类在继承BaseEntity的时候,由于没填写deleted参数名导致mybatis报错 这时候要么改application.yml里的mybatis参数&#x1f447; 要么就将BaseEntity基类的delete上加个existfalse&#x1f447;(推荐)

【ctf.show】--- md5

ctf.show_web9 1.用 dirsearch 扫目录&#xff1a;python dirsearch.py -u 网址 -e php 发现 robots.txt 2.访问 robots.txt 文件 发现 index.phps 3.访问 index.phps 发现源码 <?php $flag""; $password$_POST[password]; if(strlen…

Ventoy装机

文章目录 Ventoy安装操作系统问题U盘无法识别问题BIOS设置图片 Ventoy安装操作系统问题 当前使用的m.2&#xff08;nvm&#xff09;可以使用在台式机上。 "verification failed sercury violation"这个问题似乎与使用Ventoy创建启动盘并在启用了Secure Boot&#x…

被迫走上前端之路第六课之vue的v-for列表渲染

文章目录 语法举个栗子动态显示数组动态显示字典动态显示对象 嵌套实现 有时候我们需要动态显示一些标签重复的内容或者可迭代数据&#xff0c;如果手动一条条实现有点麻烦&#xff0c;而且代码看着不美观&#xff0c;这个时候就要用到v-for来实现 语法 其中&#xff0c;items…

速盾:cdn配置ssl

CDN&#xff08;Content Delivery Network&#xff09;是一种内容分发网络&#xff0c;它的作用是将原始服务器上的内容分发到全球各地的边缘节点上&#xff0c;以提高用户访问速度和稳定性。随着数据传输的安全性要求越来越高&#xff0c;配置SSL&#xff08;Secure Sockets L…

C++——vector类及其模拟实现

前言&#xff1a;前边我们进行的string类的方法及其模拟实现的讲解。这篇文章将继续进行C的另一个常用类——vector。 一.什么是vector vector和string一样&#xff0c;隶属于C中STL标准模板库中的一个自定义数据类型&#xff0c;实际上就是线性表。两者之间有着很多相似&…

从关键词到上下文:GPT 如何重新定义 SEO 策略

如何利用GPT技术革新SEO内容创建&#xff1f; 新的 SEO 格局 探索 SEO 的快速变化&#xff0c;重点关注从以关键字为中心的策略到更深入地了解用户意图和上下文的转变。 GPT 简介及其对内容创建、用户参与和搜索引擎优化 (SEO) 的革命性影响。 了解 GPT&#xff1a;技术范式转…

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

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

python基础知识3——列表和元组

python基础知识学习笔记之常用数据类型操作 1、列表 1.1、列表的概念和定义 概念&#xff1a;列表是有序的可变的元素集合。 定义&#xff1a; 方式1&#xff1a;[ 元素1, 元素2…] names ["zhangsan", "lisi", "wangwu"] print(names, type…

网络爬虫框架Scrapy的入门使用

Scrapy的入门使用 Scrapy概述引擎&#xff08;Engine&#xff09;调度器&#xff08;Scheduler&#xff09;下载器&#xff08;Downloader&#xff09;SpiderItem Pipeline 基本使用安装scrapy创建项目定义Item数据模型对象创建爬虫(Spider)管道pipeline来保存数据启动爬虫 其他…

消费盲返:新型返利模式引领购物新潮流

消费盲返&#xff0c;一种引领潮流的新型消费返利模式&#xff0c;其核心在于&#xff1a;消费者在平台选购商品后&#xff0c;不仅能享受优惠价格&#xff0c;更有机会获得后续订单的部分利润作为额外奖励。这种创新的返利机制&#xff0c;既提升了消费者的购物体验&#xff0…

AUTOSAR关于内存栈的分层及描述

首先关于关于内存栈的分层&#xff1a;如下图所示&#xff0c;Nvm靠近RTE的&#xff1b;MemIf居中&#xff0c;EA和FEE被包含其中。 其次关于这三层的缩写&#xff1a;可以看到EEPROM的模拟和EEPROM的抽象层。 我们可以看到 大概的数据流&#xff1a; 和大致的结构分层作用&am…