首页 > 其他分享 >深入理解ArrayList的动态扩容机制及应用

深入理解ArrayList的动态扩容机制及应用

时间:2023-09-05 18:35:30浏览次数:36  
标签:扩容 容量 int ArrayList elementData newCapacity minCapacity 动态


在java编程中,数据结构起着至关重要的作用,而ArrayList作为一种常用的动态数组,为我们在处理数据时提供了便利。其中,其独特的动态扩容机制更是为其赢得了广泛的应用。我们不管在工作还是面试中,都会遇到ArrayList,本文将深入探讨ArrayList的动态扩容机制,以便我们在工作或者面试中用到。

ArrayList简介

ArrayList是Java编程语言中的一个类,它实现了List接口,底层通过数组来存储元素。提供了对List 的添加(add)、删除(remove)、获取元素(get)等功能。其缺点是元素必须连续存储,所以增删慢,优点是查询快。ArrayList具有动态扩容的特性,这意味着它能够根据需要自动调整内部数组的大小,以适应不同数量的元素。

动态扩容详解

当我们向ArrayList 中添加元素(调用add()或者addAll())时,都调用了一个ensureCapacityInternal()方法

我们来看源码:

add()

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

addAll()

public boolean addAll(Collection<? extends E> c) {
    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityInternal(size + numNew);  // Increments modCount
    System.arraycopy(a, 0, elementData, size, numNew);
    size += numNew;
    return numNew != 0;
}

从源码可以看到,这两个方法都调用了ensureCapacityInternal()这个方法,参数是当前list的长度加上要插入的对象给个个数(单个对象的话为1,对象集合的话是集合的长度),既集合添加元素所需最小的长度

ensureCapacityInternal()

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

ensureExplicitCapacity() 方法的入参是calculateCapacity()(参数是存储实际元素的数组和集合添加元素所需最小的长度) 方法处理后的值。

calculateCapacity()

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

当前方法返回的值是如果源集合是空的,则返回 默认容量(10)和元素集合添加元素所需最小的长度值比较,值大的一个,若不为空则返回minCapacity。

深入理解ArrayList的动态扩容机制及应用_java

ensureExplicitCapacity()

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;
    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);
}

我们来详细解读下这段代码

  • int oldCapacity = elementData.length;

获取当前数组的容量,也就是elementData数组的长度,即当前存储元素的数组长度。

  • int newCapacity = oldCapacity + (oldCapacity >> 1);

计算新的容量。这里使用位运算右移1位(相当于除以2)的方式,将当前容量扩大1.5倍。
如果对 位运算符 >> 不太了解对的家人们可以看下我们上篇文章 深入解析Java中的位运算符:<<、>>和>>>

  • if (newCapacity - minCapacity < 0)

检查计算得到的新容量是否满足最小容量要求。如果不满足,则将新容量设置为最小容量minCapacity。

  • if (newCapacity - MAX_ARRAY_SIZE > 0)

检查新容量是否超过了最大数组容量限制。MAX_ARRAY_SIZE是ArrayList内部定义的一个常量,表示数组的最大容量。如果新容量超过这个限制,就调用hugeCapacity(minCapacity)方法来获得一个足够大的容量。

深入理解ArrayList的动态扩容机制及应用_数据结构_02

深入理解ArrayList的动态扩容机制及应用_数组_03

  • elementData = Arrays.copyOf(elementData, newCapacity);

使用Arrays.copyOf()方法将原有的elementData数组复制到一个新数组中,新数组的容量为计算得到的新容量newCapacity。这实现了实际的数组扩容操作。

使用注意事项和优化

  • 初始化大小

在创建ArrayList时,如果我们能够预测大致的数据量,初始化一个合适的初始大小可以减少扩容次数,从而提高性能。

  • 避免频繁扩容

频繁的扩容会带来较大的性能开销,因此尽量避免在循环中多次添加元素,以免触发多次扩容操作。

总结

ArrayList作为一种常用的数据结构,在动态扩容机制的支持下,为我们的编程工作带来了很大的便利。深入理解其动态扩容的原理和应用场景,有助于我们更好地在工作中使用ArrayList,同时在面试中也能够展现出扎实的基础知识。

无论是处理不确定数据量的业务逻辑,还是在技术面试中回答ArrayList相关问题,对其动态扩容机制的理解都将让你更加从容应对各种挑战。


标签:扩容,容量,int,ArrayList,elementData,newCapacity,minCapacity,动态
From: https://blog.51cto.com/xiuji/7378035

相关文章

  • 深入解析 MyBatis 中的 <foreach> 标签:优雅处理批量操作与动态 SQL
    在当今的Java应用程序开发中,数据库操作是一个不可或缺的部分。MyBatis作为一款颇受欢迎的持久层框架,为我们提供了一种优雅而高效的方式来管理数据库操作。在MyBatis的众多特性中,<foreach>标签无疑是一个强大的工具,它使得在SQL语句中进行动态循环迭代变得轻而易举。本文将带您深入探......
  • 掌握 MyBatis<choose>标签:优化动态查询条件的利器
    当谈到在Java应用程序中进行数据库访问时,MyBatis是一个备受欢迎的持久层框架。它的强大之处在于提供了灵活性和可定制性,使得数据库操作变得更加简便。在这篇文章中,我们将深入介绍MyBatis中的<choose>标签,它是一个有趣且功能强大的元素,用于在SQL映射文件中进行条件选择。MyBat......
  • vue3.0 el-table 动态合并单元格
    <el-tablev-resize:34style="margin:10px010px":data="tableData":header-cell-style="{background:'#F6F6F6',height:'10px','text-align':'center'}":......
  • C和C++动态库区别
    1.C语言导出动态库需要在返回值和函数之间加上__declspec(dllexport)2.C语言导出动态库需要在class和类名之间加上__declspec(dllexport)3.C++由于支持函数重载,所以在编译时要给每个函数名重新改名字(加上参数信息),而C不支持,所以C语言无法使用C++的动态库4.在C++里导出dll时,使......
  • avue表单组件后台拖拉拽框架avue-form-design在移动端vant框架与uniapp框架下的动态渲
    avue表单组件后台拖拉拽框架avue-form-design:https://github.com/sscfaith/avue-form-designavue表单组件后台拖拉拽框架avue-form-design在移动端vant框架与uniapp框架下的动态渲染转换适配待补充......
  • 15、HSSFWorkbook实现动态指定字段导出
    一、自定义注解标记对象属性:1、声明注解:importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;@Target({ElementType.METHOD,ElementType.FIELD})@Retenti......
  • 海域可视化监管:浅析海域动态远程视频智能监管平台的构建方案
    一、方案背景随着科技的不断进步,智慧海域管理平台已经成为海洋领域监管的一种重要工具。相比传统的视频监控方式,智慧海域管理平台通过建设近岸海域视频监控网、海洋环境监测网和海上目标探测网络等,可实现海洋管理的数字化转型。传统的监控方式往往需要大量人力物力,而智慧海域管理平......
  • Axure动态面板简单使用,左边点击右边查看
    1.首先先把左边的信息(不管是文字还是文本都行)准备好,然后添加动态模板 2.此时动态模板什么东西都没有,我们需要添加状态,状态就是我们要看到的信息 3.现在我们要做交互动作,让他们关联起来 4.最后预览,点击试试看 ......
  • 精简深拷贝ArrayList实例(包括递归和序列化方法)
    作者fbysss关键字:深拷贝,序列化前言:     日前一哥们问我一个有关多层ArrayList拷贝的问题,我帮他写了一个例程,感觉以后用得着,便放上来了。如果要在自身类中加入Clone功能,需要implementsICloneable接口,然后用下面的相应代码重写clone方法即可。源代码:packagecom.sss.t......
  • 动态贴纸、美颜SDK与AR:创造独特的互动体验
    目前,动态贴纸、美颜SDK、增强现实(AR)等技术是比较热门的话题,它们所结合的新兴玩法更是收到大家推崇,正潜移默化的改变我们与数字世界互动的方式。一、动态贴纸:个性化互动的开始动态贴纸,可以在实时视频或照片中添加虚拟元素,如面具、耳朵、花朵等。这些贴纸可以让用户在直播或拍摄视频......