我的编程空间,编程开发者的网络收藏夹
学习永远不晚

JavaArrayList扩容机制原理深入分析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

JavaArrayList扩容机制原理深入分析

扩容机制

ArrayList是一个底层基于数组实现的集合容器。当我们在创建ArrayList对象时,默认数组长度为10,当然也可以在创建时指定长度。之后在程序执行过程中,不断地向ArrayList中添加数据。当数据存储达到底层数组最大容量时则会触发扩容机制

扩容原理

首先创建一个新的数组,新数组的长度时原数组的1.5倍。然后调用Arrays.copyOf()方法将原数组的所有数据copy到新数组中,再将当前新添加的数据添加至新数组并返回

源码分析

先来看ArrayList类生命的几个参数

// 默认ArrayList底层数组长度为10
private static final int DEFAULT_CAPACITY = 10;
// 空数组  其他地方调用
private static final Object[] EMPTY_ELEMENTDATA = {};
// 默认长度的空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// elementData 真正存储数据的数组  ArrayList的容量就是该数组的长度 
// 默认创建空的ArrayList将在第一次调用add方法时将该数组扩容成为DEFAULT_CAPACITY = 10的容量
transient Object[] elementData;
// size代表的是当前elementData数组中存储的元素个数  并不是数组的容量! 
private int size;

当我们创建ArrayList对象并且指定长度时调用的构造器

ArrayList<> list = new ArrayList<>(12);
public ArrayList(int initialCapacity) {
    // initialCapacity就是你指定的长度
    // 逻辑判断
        if (initialCapacity > 0) {
// initialCapacity符合要求就创建新数组 长度为你指定的长度
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
// 如果initialCapacity为0则得到一个空数组
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
        }
    }

不指定长度时构造器

public ArrayList() {
    // 使用默认长度大小的数组
  this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

需要注意的是,我们不论用上述哪个构造器,首先第一步创建出来的都是空数组,但是会在第一次添加数据的时候执行不同方法进行扩容

下面我们从调用add()方法开始分析:

每次添加数据都会将size+1去进行判断,保证数组拥有至少存储这个新数据的空间

public boolean add(E e) {
    // 就此处开始一系列的扩容判断和操作
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;// 添加数据
        return true;
    }
// 下面是add方法中第一行执行的方法  此处minCapacity就是数组的最小容量  也就是当前存储的元素个数+1
private void ensureCapacityInternal(int minCapacity) {
 ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

CalculateCapacity()方法用于判断当前数组是否是默认容量的数组,如果是默认容量的数组那么此时就要确定是否是第一次添加数据

如果是第一次添加数据,那么就将返回DEFAULT_CAPACITY=10也就是minCapacity=10

如果不是第一次添加数据,就将添加新数据之后的最小容量返回

其次还要注意的是,如果在创建ArrayList对象时使用的指定长度的构造器那么就会直接返回最小容量,也就是说如果你创建ArrayList指定长度为0,那么此时就会返回minCapacity=1,指定长度为0这个清空后面给到具体分析

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

ensureExplicitCapacity()方法用于判断是否需要扩容,经过上述方法将最小容量minCapacity传入ensureExplicitCapacity方法,如果这个所需最小容量大于当前数组容量(也就是当前数组存不下这个新数据了)则触发扩容机制grow()方法,反之不会进行扩容

private void ensureExplicitCapacity(int minCapacity) {
        modCount++;// modCount++是做什么的? 我也不知道
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

在分析grow()方法之前我们先明确两个概念:

ArrayList定义了允许存储的最大容量也就是Integer允许的范围-8,如果溢出则是负数

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

Integer类型的范围是: -2的31次方~2的31次方减1

@Native public static final int MAX_VALUE = 0x7fffffff;

下面我们来看真正实现扩容的grow()方法

private void grow(int minCapacity) {
        // overflow-conscious code
    // 获取原数组容量
        int oldCapacity = elementData.length;
    // 新数组的容量是原数组容量的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
    // 判断新数组容量是否小于最小容量
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
    // 判断新容量是否超过了ArrayList允许的最大值
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
    // 调用copyOf方法将原数据全部复制到新的空数组中
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
// 超出了ArrayList容量执行hugeCapacity
    private static int hugeCapacity(int minCapacity) {
        // 因为Integer溢出则为负数,此处判断是否溢出
        if (minCapacity < 0) // overflow
            // 抛出异常  内存溢出
            throw new OutOfMemoryError();
        // 没有溢出则判断最小容量是否大于了ArrayList允许的最大值
        // 大于--> 返回Integer最大值
        // 小于--> 返回ArrayList允许的最大值
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

值得注意的是,如果当前数组是无参构造器默认生成的空数组,并且是第一次添加数据时,那么数组的长度将会直接变为10

如果当前的数组是有参构造器(指定长度)生成并且指定初始容量为0,那么在前四次调用add方法添加数据时每次扩容都是+1,只有在第五次才会执行1.5倍扩容。

因为第一次添加则是minCapacity=1,oldCapacity=0 执行int newCapacity = oldCapacity + (oldCapacity >> 1);之后newCapacity 还是0,则执行if (newCapacity - minCapacity < 0) -->newCapacity = minCapacity;也就是1,那么newCapacity 就为1,后面的三次以此类推差不多

那么至此,ArrayList就完成了扩容

到此这篇关于Java ArrayList扩容机制原理深入分析的文章就介绍到这了,更多相关Java ArrayList扩容机制内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

JavaArrayList扩容机制原理深入分析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

JavaArrayList扩容机制原理深入分析

在Java中,ArrayList是最常用的集合之一。它是一种容器,它的内部定义了一个Object类型的数组elementData,因此可用于存储任意类型的数据。我们知道,数组是长度恒定的。而ArrayList相当于是一个长度可变的动态数组,一起来看看的它的扩容机制
2023-02-22

Android消息机制原理深入分析

这篇文章主要介绍了Android消息机制原理,Android的消息机制主要是指Handler的运行机制以及Handler所附带的MessageQueue和Looper的工作过程
2022-12-09

深入剖析Android消息机制原理

在Android中,线程内部或者线程之间进行信息交互时经常会使用消息,这些基础的东西如果我们熟悉其内部的原理,将会使我们容易、更好地架构系统,避免一些低级的错误。在学习Android中消息机制之前,我们先了解与消息有关的几个类:1.Mess
2022-06-06

Go 包管理机制深入分析

前言随着 Go 语言的深入使用,其依赖管理机制也一直是各位 Gopher 热衷于探讨的话题。Go 语言的源码依赖可通过 go get 命令来获取,但自动化程度不高,于是官方提供了 Dep 这样的自动化批量管理依赖的工具。虽然 Go 语言的依
2023-06-04

ReactFiber原理深入分析

Fiber可以理解为一个执行单元,每次执行完一个执行单元,ReactFiber就会检查还剩多少时间,如果没有时间则将控制权让出去,然后由浏览器执行渲染操作,这篇文章主要介绍了ReactFiber架构原理剖析,需要的朋友可以参考下
2023-01-10

Android事件分发机制深入刨析原理及源码

Android 的事件分发机制大体可以分为三部分:事件生产、事件分发 、事件消费。事件的生产是由用户点击屏幕产生,我们这次着重分析事件的分发和消费,因为事件分发和处理联系的过于紧密,这篇文章将把事件的分发和消费放在一起分析
2023-05-16

java arraylist扩容机制原理是什么

Java中的ArrayList是基于数组实现的动态数组,其扩容机制的原理如下:1. 初始容量:当创建一个ArrayList对象时,会分配一定的初始容量,例如10个元素的容量。2. 扩容策略:当ArrayList中的元素个数超过当前容量时,需
2023-10-19

Java ArrayList扩容机制原理是什么

本文小编为大家详细介绍“Java ArrayList扩容机制原理是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java ArrayList扩容机制原理是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。扩
2023-07-05

Golangsync.Map原理深入分析讲解

go中map数据结构不是线程安全的,即多个goroutine同时操作一个map,则会报错,因此go1.9之后诞生了sync.Map,sync.Map思路来自java的ConcurrentHashMap
2022-12-17

深入理解spring的AOP机制原理

前言在软件开发中,散布于应用中多处的功能被称为横切关注点,通常来讲,这些横切关注点从概念上是与应用的业务逻辑相分离的。把这些横切关注点和业务逻辑分离出来正是AOP要解决的问题。AOP能够帮我们模块化横切关注点,换言之,横切关注点可以被描述为
2023-05-31

Spring@Lookup深入分析实现原理

这篇文章主要介绍了Spring@Lookup实现原理,我们知道在spring容器中单独的一个抽象类是不能成为一个bean的,那么有没有办法呢?这个时候我们可以使用Lookup注解
2023-01-03

Vue响应式原理深入分析

响应式就是当对象本身(对象的增删值)或者对象属性(重新赋值)发生变化时,将会运行一些函数,最常见的就是render函数,下面这篇文章主要给大家介绍了关于Vue3响应式原理的相关资料,需要的朋友可以参考下
2022-12-30

python列表中扩容机制的示例分析

这篇文章将为大家详细讲解有关python列表中扩容机制的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1、说明在对列表进行添加数据项时,如果列表内部的容量已满则会触发扩容机制。2、判定当前列表是否
2023-06-15

如何进行HashMap扩容机制源码分析

这期内容当中小编将会给大家带来有关如何进行HashMap扩容机制源码分析,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。具体看源码之前,我们先简单的说一下HashMap的底层数据结构  1、HashMap底
2023-06-02

Android权限机制深入分析讲解

Android的权限管理遵循的是“最小特权原则”,即所有的Android应用程序都被赋予了最小权限。一个Android应用程序如果没有声明任何权限,就没有任何特权
2022-12-08

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录