ArrayList扩容详解

ArrayList扩容详解本文探讨一下ArrayList的扩容过程ArrayList底层是数组elementData,用于存放插入的数据。初始大小是0,当有数据插入时,默认大小DEFAULT_CAPACITY=10。如果在创建ArrayList时指定了initialCapacity,则初始大小是ArrayList1.验证扩容的代码示例从示例中可以看到,当添加元素时,如果元素个数+1>当前数组长度【size+1>elementData.length】时,进行扩容,扩容后的数组大小是:oldC.

大家好,又见面了,我是你们的朋友全栈君。

本文探讨一下ArrayList的扩容过程

ArrayList底层是数组elementData,用于存放插入的数据。初始大小是0,当有数据插入时,默认大小DEFAULT_CAPACITY = 10。如果在创建ArrayList时指定了initialCapacity,则初始大小是ArrayList

1. 验证扩容的代码示例

从示例中可以看到,当添加元素时,如果元素个数+1> 当前数组长度 【size + 1 > elementData.length】时,进行扩容,扩容后的数组大小是: oldCapacity + (oldCapacity >> 1)

将旧数组内容通过Array.copyOf全部复制到新数组,此时新旧列表的size大小相同,但elementData的长度即容量不同

注意:扩容并不是严格的1.5倍,是扩容前的数组长度右移一位 + 扩容前的数组长度

public class SimpleTest {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        int size = 0;
        for (int i = 0; i < 100; i++) {
            list.add(i);
            if(getCapacity(list)>size) {
                 System.out.println("capacity:"+getCapacity(list) + ",size:"+list.size());
                size = getCapacity(list);
            }
        }
    }

    public static Integer getCapacity(ArrayList list) {
        Integer length = null;
        Class clazz = list.getClass();
        Field field;
        try {
            field = clazz.getDeclaredField("elementData");
            field.setAccessible(true);
            Object[] object = (Object[]) field.get(list);
            length = object.length;
            return length;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return length;
    }
}

  运行结果如下:

capacity:10,size:1
capacity:15,size:11
capacity:22,size:16
capacity:33,size:23
capacity:49,size:34
capacity:73,size:50
capacity:109,size:74

2. 扩容相关的源代码

 public boolean add(E e) {
       //调用了一ensureCapacityInternal方法,确保数组下标不越界
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

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

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

private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
       //新容量扩大到原容量的大约1.5倍,右移一位相当于原数值除以2,扩容并不是严格的1.5位
        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);
    }

3. 为什么按大约1.5倍扩容

扩容因子的大小选择,需要考虑如下情况:

  1. 扩容容量不能太小,防止频繁扩容,频繁申请内存空间 + 数组频繁复制

  2. 扩容容量不能太大,需要充分利用空间,避免浪费过多空间;

为了能充分使用之前分配的内存空间,最好把增长因子设为 1<k<2.

k=1.5时,就能充分利用前面已经释放的空间。如果k >= 2,新容量刚刚好永远大于过去所有废弃的数组容量

并且充分利用移位操作(右移一位),减少浮点数或者运算时间和运算次数

详见参见: C++ STL 中 vector 内存用尽后, 为什么每次是 2 倍的增长, 而不是 3 倍或其他值?

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/130890.html原文链接:https://javaforall.net

(0)
上一篇 2022年6月13日 上午10:16
下一篇 2022年6月13日 上午10:16


相关推荐

  • 什么软件可以激活成功教程网址_bya意思

    什么软件可以激活成功教程网址_bya意思国内激活成功教程站点大全![http://blog.csdn.net/netxiaoyue/archive/2005/01/29/273559.aspx]国内激活成功教程站点大全!(强烈推荐)【8DD资源中心】-http://www.18dd.com/精品软件秀-http://www.ohsoft.com/163软件园-http://www.soft163.com/中华激活成功教程联盟

    2025年12月7日
    26
  • frp内网穿透设置_frp内网穿透原理

    frp内网穿透设置_frp内网穿透原理十分钟教你配置frp实现内网穿透一、frp的作用利用处于内网或防火墙后的机器,对外网环境提供http或https服务。 对于http,https服务支持基于域名的虚拟主机,支持自定义域名绑定,使多个域名可以共用一个80端口。 利用处于内网或防火墙后的机器,对外网环境提供tcp和udp服务,例如在家里通过ssh访问处于公司内网环境内的主机。二、配置说明1、…

    2025年11月14日
    4
  • 鞍点[通俗易懂]

    鞍点[通俗易懂]关于“鞍点”的说法网上讲的乱七八糟,因此我特…

    2022年8月2日
    8
  • IDM插件安装、使用方法教程

    IDM插件安装、使用方法教程0x00 前言今天给大家推荐一个特别好用的下载工具 那就是互联网下载管理器 IDM 这个工具是一种可以将下载速度提升 5 倍 可以恢复和制定下载时间表的工具 可以说 IDM 是 Windows 平台老牌而功能强大的下载工具之一 软件提供了下载队列 站点抓取和映射服务器 多媒体下载 静默下载等功能 还支持多款浏览器 对于经常有文件下载需求的用户来说 是一个非常不错的选择 并且 IDM 名声在外 配合

    2026年3月19日
    2
  • java线程池参数_java线程池参数设置原则,如何设置线程池参数比较合理?[通俗易懂]

    java线程池参数_java线程池参数设置原则,如何设置线程池参数比较合理?[通俗易懂]线程池的参数应该怎样设置呢?相信对于很多的人来说这也是一个比较难的问题,下面就让我们一起来解决一下,究竟应该如何设置线程池的参数才是最合理的吧!首先在设置参数的时候,有以下的几点是我们需要考虑到的!1、下游系统抗并发的能力多线程给下游系统造成的并发等于你设置的线程数例:假如,是多线程访问数据库,那么就得考虑数据库的连接池大小设置,数据库并发太多影响其qps,会将数据库打挂等问题。假如,是访问下游系…

    2022年5月3日
    53
  • leetcode-54螺旋矩阵

    leetcode-54螺旋矩阵给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。示例 1:输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]输出:[1,2,3,6,9,8,7,4,5]示例 2:输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]输出:[1,2,3,4,8,12,11,10,9,5,6,7]提示:m == matrix.lengthn == matrix[i].length1 <= m,

    2022年8月8日
    7

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号