ArrayList扩容机制

简介: ArrayList添加元素时,先调用ensureCapacityInternal()确保容量,首次添加时默认扩容至10。add()实质为数组赋值。grow()扩容时,新容量为旧容量的1.5倍(通过位运算提升效率),并使用Arrays.copyOf()完成数据迁移。size()用于集合元素计数,length为数组属性,length()为字符串方法。

● 先来看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 倍!
    “>>”(移位运算符):>>1 右移一位相当于除2,右移n位相当于除以 2 的 n 次方。这里 oldCapacity 明显右移了1位所以相当于oldCapacity /2。对于大数据的2进制运算,位移运算符比那些普通运算符的运算要快很多,因为程序仅仅移动一下而已,不去计算,这样提高了效率,节省了资源
    通过例子探究一下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() 方法是针对泛型集合说的,如果想看这个泛型有多少元素,就调用此方法类查看!
相关文章
|
8月前
|
前端开发 安全 Java
自定义认证前端页面
本文介绍Spring Security基础配置:前端需手动创建文件夹并拷贝路径;后端新增接口与登录配置,通过SecurityConfig实现请求认证、表单登录及跳转控制,禁用CSRF。启动后访问/demo/index触发登录验证,成功后返回指定信息。(239字)
|
8月前
|
SQL 缓存 Java
MyBatis汇总
MyBatis核心配置解析:属性加载优先级为方法参数 &gt; resource/url &gt; properties体内;支持多环境配置与事务管理(JDBC/MANAGED);提供一对一、一对多、多对多映射及多种分页方式(逻辑与物理分页),并详解执行器类型与缓存机制。
|
8月前
|
Dubbo Java 应用服务中间件
Feign远程调用
本章介绍如何使用Feign替代RestTemplate实现更优雅的HTTP跨服务调用。通过引入Feign,解决服务地址硬编码、代码可读性差等问题,结合注册中心实现声明式远程调用。内容涵盖Feign基本使用、自定义配置(日志、编码器等)、连接池优化(如Apache HttpClient),并探讨继承与抽取两种最佳实践方案,提升微服务间通信的可维护性与复用性。
|
8月前
|
安全 Java 数据安全/隐私保护
SpringSecurity通用权限管理模型
本文介绍ACL、RBAC等常见权限模型。ACL基于对象授权,简单直接;RBAC则通过“用户-角色-权限-资源”模式实现灵活控制,具备最小权限、职责分离、数据抽象三大原则,并衍生出含角色继承与约束的RBAC0-RBAC3系列,助你构建系统化权限认知。(238字)
|
7月前
|
存储 人工智能 安全
深度揭秘 ooderAgent MIT 开源框架
在人工智能技术快速发展的今天,AI Agent系统已成为实现复杂任务协作的重要架构。ooderAgent(全称ooder SuperAgent)作为一套基于MIT协议的开源企业级AI能力分发与自动化协作框架,通过创新的Agent架构和SKILL管理机制,为企业提供了从简单任务到复杂流程的全场景自动化解决方案。该框架由ooder团队开发,采用SpringCloud分布式架构,于2026年1月发布最新版本v0.6.2,目前已在企业级AI应用领域展现出重要的技术价值。 本研究旨在全面剖析ooderAgent框架的技术特点与技术价值,重点关注其在技术架构设计、应用能力边界、技术创新突破以及商业价值创造
|
10月前
|
人工智能 缓存 自然语言处理
95_跨任务提示:一次提示完成多种任务
在大语言模型(LLM)应用开发中,我们常常面临需要处理多个相关任务的场景。传统方法是为每个任务单独设计提示并调用API,这不仅增加了开发复杂度,还会导致token消耗增加和响应延迟累积。跨任务提示(Multi-Task Prompting)作为一种高效的提示工程技术,能够在单个提示中集成多个相关任务,让LLM一次调用完成多种处理需求。
328 0
|
9月前
|
人工智能 测试技术
NeurlPS 2025!多伦多大学TIRE助力3D/4D 生成精准保留主体身份
TIRE提出“追踪-补全-重投影”三阶段方法,实现主体驱动的3D/4D生成。通过视频跟踪识别缺失区域,定制2D模型补全纹理,并重投影至3D空间,提升生成一致性与质量,推动动态场景生成新进展。
497 8
NeurlPS 2025!多伦多大学TIRE助力3D/4D 生成精准保留主体身份
|
8月前
|
Java Maven Spring
SpringBoot打包
本项目通过Maven打包为单一可执行JAR,内置配置文件与依赖,使用Spring Boot插件指定主类并repackage。执行`mvn clean package`构建后,通过`java -jar`运行(前台/后台),`kill -9 pid`停止服务。也可将JAR、依赖与配置分离部署,提升灵活性与维护性。(238字)
|
8月前
|
存储 缓存 Java
SpringBoot自动装配机制
本章深入解析SpringBoot自动装配机制,从@SpringBootApplication注解入手,剖析其组合注解原理。重点讲解@EnableAutoConfiguration如何通过@AutoConfigurationPackage实现包扫描、通过AutoConfigurationImportSelector加载spring.factories中的自动配置类,结合@Conditional条件注解实现智能化配置。同时解析@ComponentScan组件过滤机制及自定义排除方式,揭示SpringBoot“约定优于配置”的底层实现逻辑。(238字)
|
8月前
|
JSON 安全 Java
SpringBoot鉴权
本文介绍基于Spring Security与JWT实现客户端Token认证的完整方案,涵盖登录鉴权、Token生成与验证、角色权限控制等细节。通过自定义过滤器与认证组件,结合Redis或数据库可扩展实现高效安全的无状态认证体系,适用于Spring Boot微服务架构。

热门文章

最新文章