ArrayList扩容机制

简介: 本文解析了Java中`ArrayList`的扩容机制。

● 首先,然我们来看看Add方法

/**
*将指定的元素追加到此列表的末尾
*/
public boolean add(E e) {
   
    //添加元素之前,先调用ensureCapacityInternal方法
    ensureCapacityInternal(size + 1);  // Increments modCount!!(增量modCount)
    //这里看到ArrayList添加元素的实质就相当于为数组赋值
    elementData[size++] = e;
    return true;
}

● 再来看看ensureCapacityInternal()方法,可以看到add()方法首先调用了ensureCapacityInternal(size+1)


//得到最小扩容量
private void ensureCapacityInternal(int minCapacity) {
   
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
   
        //获取默认的容量和传入参数的较大值(第一次的较大值是DEFAULT_CAPACITY=10,minCapacity=1)
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    ensureExplicitCapacity(minCapacity);
}

当要add进第一个元素时,minCapacity为1,在Math.max()方法比较后,minCapacity为10
● ensureExplicitCapacity()方法


//判断是否需要扩容
private void ensureExplicitCapacity(int minCapacity) {
   
    modCount++;
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        //调用grow()方法进行扩容,调用此方法代表已经开始扩容了
        grow(minCapacity);
}

我们可以来分析一下

  1. 当我们要add进第一个元素到ArrayList时,elementData.length为0(因为还是一个空的list,里面还没有数据,所以没有进行扩容,默认扩容10),因为执行了ensureCapacityInternal()方法,所以minCapacity此时为10。此时,minCapacity - elemetData.length > 0(minCapacity=10,elemetData.length=0)成立,所以会进入==grow(minCapacity)==方法。
  2. 当add第2个元素时,minCapacity为2,此时elementData.length(容量)在添加第一个元素后扩容成10了。此时,minCapacity - elementData.length > 0不成立,所以不会进入(执行)==grow(minCapacity)==方法。
  3. 添加第3、4…到第10个元素时,依然不会执行==grow()==方法,数组容量都为10。
    知道添加第11个元素,minCapacity(为11)比elementData.length(为10)要大。进行grow方法进行扩容
  4. grow方法
    private void grow(int minCapacity) {
         
     // oldCapacity为旧容量,newCapacity为新容量
     int oldCapacity = elementData.length;//(0,10,15)
     //将oldCapacity右移一位,其效果相当于oldCapacity/2;
     // 我们知道位运算的速度远远快于整除运算,整句运算式的结果就是将新容量更新为旧容量的1.5倍
     int newCapacity = oldCapacity + (oldCapacity >> 1);
     // 然后检查新容量是否大于最小需要容量,若还是小于最小需要容量,那么久把最小需要容量当作数组的新容量
     if (newCapacity - minCapacity < 0)
         newCapacity = minCapacity;
     //判断新容量是否大于集合的最大容量(一般大不了)
     if (newCapacity - MAX_ARRAY_SIZE > 0)
         newCapacity = hugeCapacity(minCapacity);
     // 给elementData从新赋值(10,15)
     elementData = Arrays.copyOf(elementData, newCapacity);
    }
    

int newCapacity = oldCapacity + (oldCapacity >> 1),所以 ArrayList 每次扩容之后容量都会变为原来的 1.5 倍!
这里,可以通过例子来探究一下grow()方法
● 当add第一个元素时,oldCapacity为0,经比较后第一个if判断成立,newCapacity = minCapacity(为10)。但是第二个if判断不会成立,即newCapacity不比MAX_ARRAY_SIZE大,则不会进入hugeCapacity方法。数组容量为10,add方法中return true,size增为1。
● 当add第11个元素进入grow方法时,newCapacity为15,比minCapacity(为11)大,第一个if判断不成立。新容量没有大于数组最大size,不会进入hugeCapacity方法。数组容量扩为15,add方法中rerurn,true,size增为11。
● 以此类推…
这里补充一点比较重要,但是容易被忽视掉的知识点:
● java中的length属性是针对数组说的,比如说你声明了一个数组,想知道这个数组的长度则用到了length这个属性。
● java中的length() 方法是针对字符串说的,如果想看这个字符串的长度则用到 length() 这个方法。
● java中的size() 方法是针对泛型集合说的,如果想看这个泛型有多少元素,就调用此方法类查看!

相关文章
|
存储 Java
ArrayList自动扩容(详细篇)
ArrayList自动扩容(详细篇)
898 1
|
设计模式 前端开发 搜索推荐
前端必须掌握的设计模式——模板模式
模板模式(Template Pattern)是一种行为型设计模式,父类定义固定流程和步骤顺序,子类通过继承并重写特定方法实现具体步骤。适用于具有固定结构或流程的场景,如组装汽车、包装礼物等。举例来说,公司年会节目征集时,蜘蛛侠定义了歌曲的四个步骤:前奏、主歌、副歌、结尾。金刚狼和绿巨人根据此模板设计各自的表演内容。通过抽象类定义通用逻辑,子类实现个性化行为,从而减少重复代码。模板模式还支持钩子方法,允许跳过某些步骤,增加灵活性。
905 11
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细解析Spring Bean的生命周期及其核心概念,并深入源码分析。Spring Bean是Spring框架的核心,由容器管理其生命周期。从实例化到销毁,共经历十个阶段,包括属性赋值、接口回调、初始化及销毁等。通过剖析`BeanFactory`、`ApplicationContext`等关键接口与类,帮助你深入了解Spring Bean的管理机制。希望本文能助你更好地掌握Spring Bean生命周期。
1459 1
|
存储 安全 算法
Java面试题之Java集合面试题 50道(带答案)
这篇文章提供了50道Java集合框架的面试题及其答案,涵盖了集合的基础知识、底层数据结构、不同集合类的特点和用法,以及一些高级主题如并发集合的使用。
1531 1
Java面试题之Java集合面试题 50道(带答案)
|
10月前
|
应用服务中间件 nginx Docker
静态资源管理:Nginx在Docker中的部署
部署Nginx到Docker中作为静态资源服务器是一种既简单又高效的方法,可以节省时间和资源,并能确保一致性和可扩展性。我们通过编写Dockerfile指定了基础镜像和所需指令,编写Nginx配置管理请求处理,构建自定义Docker镜像,并运行容器以启动服务。这一过程即符合开发规范,也保证了资源的高效管理和访问速度。
423 13
|
流计算 UED
「Mac畅玩鸿蒙与硬件48」UI互动应用篇25 - 简易购物车功能实现
本篇教程将带你实现一个简易购物车功能。通过使用接口定义商品结构,我们将创建一个动态购物车,支持商品的添加、移除以及实时总价计算。
464 69
「Mac畅玩鸿蒙与硬件48」UI互动应用篇25 - 简易购物车功能实现
|
消息中间件 JSON Java
Spring Boot、Spring Cloud与Spring Cloud Alibaba版本对应关系
Spring Boot、Spring Cloud与Spring Cloud Alibaba版本对应关系
35085 1
线程池的核心参数有哪些 ?
corePoolSize 核心线程数量 maximumPoolSize 最大线程数量 keepAliveTime 线程保持时间,N个时间单位 unit 时间单位(比如秒,分) workQueue 阻塞队列 threadFactory 线程工厂 handler 线程池拒绝策略
|
机器学习/深度学习 监控 API
基于云计算的机器学习模型部署与优化
【8月更文第17天】随着云计算技术的发展,越来越多的数据科学家和工程师开始使用云平台来部署和优化机器学习模型。本文将介绍如何在主要的云计算平台上部署机器学习模型,并讨论模型优化策略,如模型压缩、超参数调优以及分布式训练。
1884 2
|
调度 数据库 计算机视觉
并行和并发的区别(详细)
并行和并发的区别(详细)