一文了解 ArrayList 的扩容机制

news2024/11/16 10:28:18

了解 ArrayList

在 Java 中常用集合类之间的关系如下图所示:

在这里插入图片描述

从图中可以看出 ArrayList 是实现了 List 接口,并是一个可扩容数组(动态数组),它的内部是基于数组实现的。它的源码定义如下:

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
}
  • ArrayList 可以实现所有可选择的列表操作,允许所有的元素,包括空值。ArrayList 还提供了内部存储 List 的方法,它能够完全替代Vector,只有一点例外,ArrayList 不是线程安全的容器。

  • ArrayList 有一个容量的概念,这个数组的容量(size)就是 List 用来存储元素的容量。

  • ArrayList 不是线程安全的容器,如果多个线程中至少有两个线程修改了 ArrayList 的结构的话就会导致线程安全问题,作为替代条件可以使用线程安全的 List,应使用 Collections.synchronizedList

    List list = Collections.synchronizedList(new ArrayList<>());
    
  • ArrayList 具有 fail-fast 快速失败机制,能够对 ArrayList 作出失败检测。当在迭代集合的过程中该集合在结构上发生改变的时候,就有可能会发生 fail-fast,即抛出ConcurrentModificationException异常。

通过源码分析 ArrayList 的扩容机制

当使用空参构造器进行创建 ArrayList 的时候,实际上给 elementData 初始化赋值的是一个空数组 {}

//数组列表的大小(包含的元素数),初始化为 0
private int size;
//存储数组列表元素的数组缓冲区。
transient Object[] elementData;
//默认初始化容量为10
private static final int DEFAULT_CAPACITY = 10;
//默认空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//使用空参构造器创建 ArrayList 时,实际上初始化赋值的是一个空数组
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

当首次调用 add(E e) 方法进行添加第一个元素时,会首先调用 ensureCapacityInternal 方法,传入参数 1

//将指定的元素追加到此列表的末尾
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

ensureCapacityInternal 方法中,会调用 calculateCapacity 方法,传入参数为 elementData,1

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

calculateCapacity 方法中,判断 elementData 是否为空数组,由于是初始化赋值的是一个空数组 {},所以符合 if 条件,返回 (DEFAULT_CAPACITY, minCapacity)【10,1】 中大的那个,此时返回 10

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

接着返回到 ensureCapacityInternal 方法中,继续调用 ensureExplicitCapacity 方法验证是否需要扩容,传入参数 10 ,此时 minCapacity=10,elementData.length=0 ,相减小于0,执行 grow 方法扩容,传入参数 10,当添加第2-10个元素时,不会执行 grow 方法,一直到数组已经满元素时才执行 grow 方法扩容:

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

grow 方法中,此时 minCapacity=10,oldCapacity=0,newCapacity=0 ,符合 newCapacity - minCapacity < 0 条件,执行 newCapacity = minCapacity; 不满足 newCapacity - MAX_ARRAY_SIZE > 0 ,执行 Arrays.copyOf() 方法将 elementData 指向的数组中的元素复制到新的数组中,新的数组长度为 10,并让 elementData 指向新的数组,int newCapacity = oldCapacity + (oldCapacity >> 1) 完成1.5倍扩容。

private void grow(int minCapacity) {
    // overflow-conscious code
    int 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);
}

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

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

相关文章

漫谈广告机制设计 | 从维纳斯的七个香吻说起

情人节就要来了&#xff0c;节日快乐&#xff0c;让我们从一段浪漫的爱情故事开始。维纳斯的七个香吻-最早的广告费传说在古罗马一个小国&#xff0c;国王有一个女儿叫普绪喀&#xff0c;长得很漂亮&#xff0c;以至于被人们认为是爱神维纳斯下凡&#xff0c;而不再去供奉真正的…

DM8:DMDSC共享存储集群搭建-共享存储绑定

DM8:DMDSC共享存储集群搭建-共享存储绑定环境介绍&#xff1a;1 发现共享磁盘2 对共享存储进行分区格式化2.1 格式化成功但不可用2.2 解决问题修改错误的分区格式3 配置/etc/rc.d/rc.local3.1 编辑文件&#xff08;两个节点配置相同&#xff09;3.2 使rc.local生效4 重启操作系…

cadence SPB17.4 S032 - allegro - 保存/载入光绘层定义

文章目录cadence SPB17.4 S032 - allegro - 保存/载入光绘层定义概述保存光绘层在新板子中载入已经保存的相同类型老板子定义好的光绘层定义文件碎碎念ENDcadence SPB17.4 S032 - allegro - 保存/载入光绘层定义 概述 以前布线完成, 准备出板厂文件时, 总是要手工重新建立光绘…

如何在40岁退休?

如何在40岁退休&#xff1f; 我以前在高校工作&#xff0c;很多老师最关心一件事&#xff0c;就是何时退休。 现在有很多消息&#xff0c;官方渠道都透露&#xff0c;退休年龄将推迟&#xff0c;具体方案年底就会出台。一个人以后要工作更长的年限&#xff0c;才会退休。 表面上…

CSP Bypass-low 通关详解

1、从这里跨域看到&#xff0c;我们跨域引用外部的Js脚本&#xff0c;它会自动包含并使用 2、此时我们在另外一个web服务器上写下一个csp.html脚本&#xff0c;用来做弹窗&#xff0c;脚本内容写&#xff1a; <!DOCTYPE html> <html lang"en"> <head…

【电商开发手册】订单-下单

下单需求 所谓下单&#xff0c;本质上就是买卖双方通过确认一系列信息并且签订电子合同的过程 在电商平台的下单过程中&#xff0c;也需要确定买卖双方的一系列信息&#xff1a; 买方&#xff1a;用户确认收货地址、支付方式、配送方式等等 卖方&#xff1a;卖方需要进行供…

一文详解工业知识模型互联平台MoHub

1月8日&#xff0c;MWORKS 2023产品发布会落下帷幕。会上&#xff0c;同元软控隆重推出了云原生的工业知识模型互联平台MoHub&#xff0c;引起广泛关注。本文将从服务定位、架构方案、核心服务、持续运营等方面对MoHub平台进行全面介绍。1 MoHub平台的服务定位装备数字化的必要…

C语言学习笔记-命令行参数

在图形界面普及之前都使用命令行界面。DOS和UNIX就是例子。Linux终端提供类UNIX命令行环境。 命令行&#xff08;command line&#xff09;是在命令行环境中&#xff0c;用户为运行程序输入命令的行。命令行参数&#xff08;command-line argument&#xff09;是同一行的附加项…

概率统计之概率篇

概率统计之概率篇 一 随机变量及其四种研究方法 为了更深入地研究随机现象&#xff0c;需要把随机试验的结果数量化&#xff0c;也就是要引进随机变量来描述随机试验的结果。 一般地&#xff0c;把表示随机现象的各种结果或描述随机事件的变量叫做随机变量。随机变量通常用大…

Java-Deque和Queue的使用、辨析和实战案例

0.前言 在数据结构与算法中&#xff0c;队列是被经常使用的一种数据结构&#xff0c;总体上构成较为简单&#xff0c;但是Java在实际使用时易用错&#xff0c;经常会。比如 poll() 方法&#xff0c;add() 方法&#xff0c;offer() 方法&#xff0c;addFirst()方法&#xff0c;r…

论文投稿指南——中文核心期刊推荐(石油、天然气工业 3)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

uni-app ①

文章目录一、uni-app简介学习 uniapp 本质uniapp 优势uni-app 和 vue 的关系uni-app 和小程序有什么关系uniapp 与 web 代码编写区别课程内容学习重点知识点一、uni-app 简介 uni-app 是一个使用 Vue.js 进行 开发所有前端应用的框架。开发者编写一套代码&#xff0c;即可发布…

从数据备份保护到完整生命周期管理平台,爱数全新发布 AnyBackup Family 8

编辑 | 宋慧 出品 | CSDN 云计算 从2003年创业&#xff0c;开始做数据备份技术&#xff0c;爱数已经走过了近20年的时间。现在&#xff0c;数据的价值被越来越多的业界与用户看到&#xff0c;数据分析应用赛道近年一直持续火热。而现在的爱数在做的&#xff0c;已经从数据的备…

【Python实战】神仙运气—快看看你的彩票:2千多万元大奖无人领,马上就过期了,下一期的中奖者会是你吗?(纯技术交流)

前言 越努力越幸运 哈喽~我是栗子同学&#xff01; 特别注意&#xff1a;不管是沉迷赌球&#xff0c;还是沉迷购彩&#xff0c;都是不可取的。本文纯是一个技术学习内容。 听说关注我的人会暴富哦&#xff01;、 所有文章完整的素材源码都在&#x1f447;&#x1f447; 粉丝…

数据仓库原理 - 概念、架构、建模方法

目录1、介绍1.1 数据仓库诞生原因1.2 数据仓库概述1.3 数仓的技术实现1.4 MPP&分布式架构MPP架构分布式架构MPP分布式架构1.5 常见产品2、架构2.1 架构图ETLODSCDMADS2.2 ETL流程数据抽取数据转换数据加载ETL工具2.3 数据积存操作数据层ODS2.4 数据分析数据明细层DWD数据汇…

【scipy.sparse包】Python稀疏矩阵详解

【scipy.sparse包】Python稀疏矩阵 文章目录【scipy.sparse包】Python稀疏矩阵1. 前言2. 导入包3. 稀疏矩阵总览4. 稀疏矩阵详细介绍4.1 coo_matrix4.2 dok_matrix4.3 lil_matrix4.4 dia_matrix4.5 csc_matrix & csr_matrix4.6 bsr_matrix5. 稀疏矩阵的存取5.1 用save_npz保…

MATLAB 遗传算法

✅作者简介&#xff1a;人工智能专业本科在读&#xff0c;喜欢计算机与编程&#xff0c;写博客记录自己的学习历程。 &#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&…

CSS布局之详解

在开发前端的时候&#xff0c;界面布局尤为重要&#xff0c;要布局的非常合理&#xff0c;好看&#xff0c;css是必不可少的&#xff0c;然后是各种布局&#xff0c;使用这些布局&#xff0c;进行混合搭配&#xff0c;最终的目的都是开发一个完整的界面。前端的技术变化是五花八…

mybatis-plus ---1

mybatis-plus 在mybatis的基础上只做加强&#xff0c;不做删减。 一个简单的mybatis-plus案例 结构图 创建一个springboot工程 添加依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0…

Linux(Linux各目录结构详解)

我们知道Linux系统是一个文件系统&#xff0c;它的文件系统就类似windows系统下的磁盘文件系统。 我们连接上一台linux系统的服务器。 输入命令 &#xff1a; ls / 我们可以看到 linux系统的根目录下有这些目录 bin boot data dev etc hbr home lib lib64 lostfoun…