【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) {
        //如果初始化的大小大于0
        if (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();
        //如果元素个数不为0
        if ((size = a.length) != 0) {
            //如果元素列表是一个ArrayList类型
            if (c.getClass() == ArrayList.class) {
                //把a赋给elementData
                elementData = 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) {
        //确保内部容量 传入当前集合中的元素个数在加上1
        ensureCapacityInternal(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 code
        if (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) // overflow
            throw new OutOfMemoryError();
        // 如果最小容量比数组最大容量大,返回整形的最大值,否则的话就是等于数组最大值
        // 不再扩充1.5倍了
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【IDEA+通义灵码插件】实现属于你的大模型编程助手

1、前言 大模型到底该以一种什么方式落地&#xff0c;从而嵌入我们的工作当中&#xff0c;助力我们工作效率的提升&#xff0c;其实最好的方式也许就是虚拟助手的方式&#xff0c;就像钢铁侠的"贾维斯"一样&#xff0c;随叫随到能回答问题&#xff0c;能自动的解决一…

python函数参数中独立星号*的作用

python函数中间有一个&#xff08;&#xff09;分隔&#xff0c;星号后面为*命名关键字参数&#xff0c;星号本身不是参数**。命名关键字参数&#xff0c;在函数调用时必须带参数名字进行调用。如下例子&#xff1a;

【Golang入门教程】Go语言变量的初始化

文章目录 强烈推荐引言举例多个变量同时赋值总结强烈推荐专栏集锦写在最后 强烈推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站:人工智能 推荐一个个人工作&#xff0c;日常中比较常…

深入剖析哈希表:以Java中的HashMap为例

哈希表是一种非常高效的数据结构&#xff0c;它允许我们以接近常数的时间复杂度进行插入、删除和查找操作。在Java中&#xff0c;HashMap类是实现哈希表的一个非常流行的工具。本文将深入探讨哈希表的工作原理&#xff0c;并通过Java代码来展示HashMap的使用和内部机制。 一、…

Linux 动静态库的制作,使用和加载

Linux 动静态库的制作,使用和加载 一.前置说明1.mylib.h2.mylib.c3.mymath.h mymath.c4.如何制作库 二.动静态库的制作1.静态库的制作1.制作2.使用一下静态库,验证是否成功打包 2.动态库的制作1.编译.c源文件文件生成.o目标文件2.打包生成动态库3.编写makefile文件,自动化制作动…

基于Springboot+vue的鲜花销售商城网站

摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;鲜花销售商城当然也不能排除在外。鲜花销售商城是以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#x…

多线程的学习1

多线程 线程是操作系统能够进入运算调度的最小单位。它被包含在进程之中&#xff0c;是进程中的实际运作单位。 进程&#xff1a;是程序的基本执行实体。 并发&#xff1a;在同一个时刻&#xff0c;有多个指令在单个CPU上交替执行。 并行&#xff1a;在同一时刻&#xff0c…

程序汪若依微服务华为云Linux部署保姆教程

若依官方有3个版本&#xff0c;程序汪以前已经出了对应的安装部署视频教程 单应用版本 前后分离版本 微服务版本 本视频是若依微服务版本&#xff0c;如果基础的环境软件都不会安装建议看下程序汪的单应用和前后端分离版本教程&#xff0c; 欢迎点击进入 &#xff08;单应…

全局UI方法-弹窗二-列表选择弹窗(ActionSheet)

1、描述 定义列表弹窗 2、接口 ActionSheet.show(value:{ title: string | Resource, message: string | Resource, autoCancel?: boolean, confrim?: {value: string | Resource, action: () > void }, cancel?: () > void, alignment?: DialogAlignment, …

Lightguide

Resolve Assembly Challenges with Projected AR Workflows The future of assembly is here. It’s not just about automation, it’s about empowering your workforce with the best possible digital toolset. LightGuide AR is a powerful addition to your Industry 4.…

基于单片机的便携式瓦斯检测仪系统设计

**单片机设计介绍&#xff0c;基于单片机的便携式瓦斯检测仪系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的便携式瓦斯检测仪系统设计是一个针对煤矿等工业环境中瓦斯气体浓度检测的重要项目。以下是该设计…

C++template之类模版进一步了解

前言&#xff1a;这一篇是在我的上一篇文章的基础上&#xff0c;再进一步所写的。 链接&#xff1a;CTemplate&#xff1c;&#xff1e;模版的介绍及深度解析-CSDN博客 一、类模板实例化 1.非类型模版参数 类型模版参数&#xff1a;就是跟在 class后面或者typename后的类型 非…

Java NIO和IO之间的区别

前言 NIO&#xff08;New IO&#xff09;&#xff0c;这个库是在JDK1.4中才引入的。NIO和IO有相同的作用和目的&#xff0c;但实现方式不同&#xff0c;NIO主要用到的是块&#xff0c;所以NIO的效率要比IO高很多。在Java API中提供了两套NIO&#xff0c;一套是针对标准输入输出…

WebPack的使用及属性配、打包资源

WebPack(静态模块打包工具)(webpack默认只识别js和json内容) WebPack的作用 把静态模块内容压缩、整合、转译等&#xff08;前端工程化&#xff09; 1️⃣把less/sass转成css代码 2️⃣把ES6降级成ES5 3️⃣支持多种模块文件类型&#xff0c;多种模块标准语法 export、export…

企业如何有效防止员工偷懒磨洋工?

在当今竞争激烈的商业环境中&#xff0c;企业要想保持竞争力和提高效益&#xff0c;就必须确保员工不偷懒不磨洋工。然而&#xff0c;要有效防止员工偷懒磨洋工并非易事&#xff0c;需要企业采取一系列措施来引导和监督员工的工作状态。 下面就分享三个有效防止员工偷懒磨洋工…

unity3d for web

时光噶然 一晃好多年过去了&#xff08;干了5年的u3d游戏&#xff09;&#xff0c;记得最后一次使用的版本好像是 unity 2017。 那个是 unity3d for webgl 还需要装个插件。用起来很蛋疼。 最近做一个小项目 在选择是用 Layabox 还是 cocosCreate 的时候 我想起了老战友 Uni…

DeepMind终结大模型幻觉?标注事实比人类靠谱、还便宜20倍,全开源

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 新建了人工智能中文站https://ai.weoknow.com 每天给大家更新可用的国内可用chatGPT资源​ 发布在https://it.weoknow.com 更多资源欢迎关注 ​ DeepMind 这篇论文一出&#xff0c;人类标注者的饭碗也要被砸了吗&a…

警惕.360勒索病毒:如何预防.360勒索病毒攻击

导言&#xff1a; 在网络安全领域&#xff0c;勒索病毒是一种非常危险的恶意软件&#xff0c;它以其独特的加密方式和高昂的赎金要求&#xff0c;给个人和企业带来了严重的损失。.360勒索病毒便是其中之一&#xff0c;它属于BeijingCrypt勒索病毒家族&#xff0c;具有高度的隐…

2024 年广西职业院校技能大赛高职组《云计算应用》赛项样卷

#需要资源&#xff08;软件包及镜像&#xff09;或有问题的&#xff0c;可私博主&#xff01;&#xff01;&#xff01; #需要资源&#xff08;软件包及镜像&#xff09;或有问题的&#xff0c;可私博主&#xff01;&#xff01;&#xff01; #需要资源&#xff08;软件包及镜…

iOS网络抓包工具全解析

摘要 本文将深入探讨iOS平台上常用的网络抓包工具&#xff0c;包括Charles、克魔助手、Thor和Http Catcher&#xff0c;以及通过SSH连接进行抓包的方法。此外&#xff0c;还介绍了克魔开发助手作为iOS应用开发的辅助工具&#xff0c;提供的全方面性能监控和调试功能。 在iOS应…