ArrayList扩容机制

简介: ArrayList的add方法添加元素时,先调用ensureCapacityInternal()确保容量。首次添加时,最小容量设为10,触发扩容;后续添加若超出当前容量,则调用grow()将容量扩为原来的1.5倍。grow()通过位运算高效计算新容量,确保集合动态扩展性能。注意:length用于数组,length()用于字符串,size()用于集合。

先来看Add方法
再来看看ensureCapacityInternal()方法,可以看到add()方法首先调用了ensureCapacityInternal(size+1)
当要add进第一个元素时,minCapacity为1,在Math.max()方法比较后,minCapacity为10
ensureExplicitCapacity()方法
我们来仔细分析一下
当我们要add进第一个元素到ArrayList时,elementData.length为0(因为还是一个空的list,里面还没有数据,所以没有进行扩容,默认扩容10),因为执行了ensureCapacityInternal()方法,所以minCapacity此时为10。此时,minCapacity - elemetData.length > 0(minCapacity=10,elemetData.length=0)成立,所以会进入==grow(minCapacity)==方法。
当add第2个元素时,minCapacity为2,此时elementData.length(容量)在添加第一个元素后扩容成10了。此时,minCapacity - elementData.length > 0不成立,所以不会进入(执行)==grow(minCapacity)==方法。
添加第3、4…到第10个元素时,依然不会执行==grow()==方法,数组容量都为10。
知道添加第11个元素,minCapacity(为11)比elementData.length(为10)要大。进行grow方法进行扩容
grow方法
Java
运行代码
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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() 方法是针对泛型集合说的,如果想看这个泛型有多少元素,就调用此方法类查看!

相关文章
|
7月前
|
人工智能 API 调度
从“会用 AI”到“指挥 AI”:AI调度官能力模型解析
AI调度官是面向多模型协同的新型系统角色,聚焦任务拆解、能力编排与运行约束,实现AI能力的统一调度、闭环管控与稳定执行,支撑可扩展、可解释、可持续演进的智能协同体系。
474 0
|
8月前
|
消息中间件 Shell Linux
RabbitMQ部署指南
本文介绍RabbitMQ在CentOS7下基于Docker的单机与集群部署方案,涵盖镜像安装、DelayExchange插件配置、普通模式与镜像模式集群搭建,并详解仲裁队列使用及集群扩容方法,助力实现高可用消息队列服务。
|
7月前
|
机器学习/深度学习 SQL 数据挖掘
Pandas 入门指南
Pandas是Python最核心的数据分析库,基于NumPy构建,提供高效、直观的结构化数据处理能力。其核心数据结构DataFrame(二维表格)和Series(一维序列)支持混合类型、自动索引对齐、缺失值处理与向量化运算,轻松完成清洗、筛选、分组、聚合等任务,是数据获取、分析到建模准备的全流程基石。(239字)
966 13
|
8月前
|
SQL 容灾 Nacos
Seata的部署和集成
本文介绍Seata分布式事务框架的部署与微服务集成。首先下载并解压Seata Server,修改配置文件application.yml,并在Nacos中配置seataServer.properties及数据库信息。创建seata数据库并运行SQL脚本初始化事务表。启动TC服务后,注册至Nacos。各微服务引入Seata依赖,配置application.yml连接TC。为实现高可用,搭建多节点TC集群,通过Nacos统一管理事务组映射,实现异地容灾与动态切换。微服务从Nacos读取client.properties,灵活绑定TC集群,提升系统稳定性与可维护性。(238字)
|
8月前
|
关系型数据库 应用服务中间件 Nacos
Nacos配置中心
本章详解Nacos配置中心实战:实现微服务配置统一管理,支持热更新、配置共享与优先级控制,并搭建高可用集群,提升系统稳定性。
|
8月前
|
SQL Java 数据库连接
持久层框架MyBatisPlus
MyBatisPlus是MyBatis的增强框架,简化单表CRUD操作,内置分页、条件构造器、代码生成等功能,支持逻辑删除、枚举处理与JSON字段映射,提升开发效率。
|
8月前
|
负载均衡 Java Nacos
Gateway服务网关
网关是微服务的统一入口,实现请求路由、权限控制与限流。基于Spring Cloud Gateway可快速搭建高性能网关,支持断言与过滤器灵活配置,并解决跨域问题,提升系统安全性和可维护性。
|
并行计算 数据处理 调度
《打破枷锁:Python多线程GIL困境突围指南》
全局解释器锁(GIL)是CPython解释器中的一项机制,旨在简化内存管理,但同时也限制了多线程并行性能,尤其是在多核处理器上。本文深入剖析GIL的本质及其对CPU密集型任务的局限性,同时探讨突破GIL限制的有效策略,包括多进程编程、C扩展模块、异步编程以及第三方库的应用。通过合理选择这些方法,开发者可以在不同场景下优化Python程序性能,充分发挥硬件潜力,实现高效并发编程。
470 11
送福利!FlowBench客户端首批内测邀请函
魔搭AIGC搭子们,集合啦!ModelScope x FlowBench 团队
502 3
|
算法 搜索推荐 Java
Java中的Sort
Java中的排序机制主要通过`Arrays.sort()`和`List.sort()`实现。`Arrays.sort()`支持多种排序算法,包括归并排序(`legacyMergeSort`)和TimSort。`legacyMergeSort`采用递归分割数组并合并的方式,适用于小规模数据的插入排序优化。TimSort则结合了归并排序和插入排序的优点,通过分段处理和合并优化排序性能,特别适合处理部分有序的数据。对于数值排序,Java还提供了`DualPivotQuicksort`算法。而`List.sort()`则是将列表转化为数组进行排序后再写回列表。
422 2

热门文章

最新文章