当前位置: 首页 > news >正文

java打卡学习3:ArrayList扩容机制

ArrayList扩容机制概述

ArrayList是基于动态数组实现的集合类,当元素数量超过当前数组容量时,会自动触发扩容机制。其核心目的是平衡内存占用与性能开销。

默认初始容量

  • 未指定初始容量时,默认创建一个空数组(JDK 1.8+),首次添加元素时扩容至默认容量10
  • 指定初始容量可通过构造函数ArrayList(int initialCapacity),直接初始化对应大小的数组。

扩容触发条件

当调用add()方法添加元素时,若当前元素数量size + 1 > 数组长度,即数组已满,触发扩容。

扩容规则

  1. 计算新容量:新容量为旧容量的1.5倍(即int newCapacity = oldCapacity + (oldCapacity >> 1))。
  2. 边界检查:若新容量仍不足所需最小容量(如一次性添加多个元素),则直接采用所需容量。
  3. 最大值限制:新容量不得超过Integer.MAX_VALUE - 8,否则抛出OutOfMemoryError
  4. 数组拷贝:通过Arrays.copyOf()创建新数组,并将旧数据复制到新数组。

示例代码片段

// JDK 1.8中的扩容核心逻辑(简化版) private void grow(int minCapacity) { int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity); }

性能优化建议

  • 预分配容量:若已知大致元素数量,初始化时指定容量避免多次扩容。
  • 批量操作:优先使用addAll()而非循环add(),减少扩容次数。

与Vector对比

Vector默认扩容为2倍,且线程安全但性能较低。ArrayList在非线程安全场景下更高效。

前端视角理解:

ArrayList扩容机制与前端概念的类比

ArrayList的扩容机制是指当数组容量不足时,自动创建一个更大的新数组,并将原有元素复制到新数组中。这一机制可以类比到前端开发中的某些场景:

动态DOM元素加载
类似于ArrayList在容量不足时扩容,前端页面在滚动加载更多内容时,会动态创建新的DOM元素并插入到页面中。两者都涉及动态扩展和性能优化。

虚拟列表技术
前端框架(如React/Vue)的虚拟列表仅渲染可视区域的DOM元素,当滚动时动态替换内容。这与ArrayList按需扩容的思路一致,避免一次性占用过多内存。

响应式布局的断点处理
CSS媒体查询在不同屏幕尺寸下应用不同的布局规则,类似于ArrayList根据当前size判断是否需要扩容。两者都是基于阈值触发的动态调整机制。

核心相似点

按需分配原则
ArrayList在add()时检查容量,前端在用户交互时加载资源,均遵循延迟分配的优化策略。

扩容/渲染的性能损耗
ArrayList扩容涉及数组复制,前端DOM操作会触发重排重绘。两者都需要权衡频率与单次操作的代价。

预分配优化
ArrayList可指定初始容量,前端可通过preload/prefetch提前加载资源,减少后续延迟。

差异点

触发时机
ArrayList扩容由API调用直接触发,前端动态加载通常由用户行为(如滚动)间接触发。

扩容粒度
ArrayList通常按固定倍数(如1.5倍)扩容,前端可能按需加载单条数据或分页批量加载。

实际应用示例

// 类似ArrayList扩容的前端懒加载实现 const lazyLoad = (() => { let loadedItems = 10; // 初始容量 const loadMore = () => { const newItems = loadedItems * 1.5; // 模拟扩容因子 renderItems(loadedItems, newItems); loadedItems = newItems; }; return { loadMore }; })();

这种类比有助于理解不同领域的容量管理策略,但需注意前端场景通常更强调事件驱动和异步处理特性。

今日练习:

手写简易ArrayList实现

ArrayList是基于数组实现的动态扩容列表,以下是核心功能的简化实现代码(Java版本):

public class SimpleArrayList<E> { private static final int DEFAULT_CAPACITY = 10; private Object[] elementData; private int size; public SimpleArrayList() { this.elementData = new Object[DEFAULT_CAPACITY]; } public SimpleArrayList(int initialCapacity) { if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else { throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity); } } }

添加元素方法

public boolean add(E e) { ensureCapacityInternal(size + 1); elementData[size++] = e; return true; } private void ensureCapacityInternal(int minCapacity) { if (minCapacity - elementData.length > 0) { grow(minCapacity); } } private void grow(int minCapacity) { int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); // 1.5倍扩容 if (newCapacity - minCapacity < 0) { newCapacity = minCapacity; } elementData = Arrays.copyOf(elementData, newCapacity); }

查询与删除操作

public E get(int index) { rangeCheck(index); return (E) elementData[index]; } public E remove(int index) { rangeCheck(index); E oldValue = (E) elementData[index]; int numMoved = size - index - 1; if (numMoved > 0) { System.arraycopy(elementData, index+1, elementData, index, numMoved); } elementData[--size] = null; // 清除引用 return oldValue; } private void rangeCheck(int index) { if (index >= size || index < 0) { throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); } }

迭代器实现

public Iterator<E> iterator() { return new Itr(); } private class Itr implements Iterator<E> { int cursor; // 当前元素索引 int lastRet = -1; // 最后返回的元素索引 public boolean hasNext() { return cursor != size; } public E next() { int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = SimpleArrayList.this.elementData; cursor = i + 1; return (E) elementData[lastRet = i]; } }

关键设计要点

  • 动态扩容机制:当数组空间不足时,按原容量的1.5倍扩容(JDK标准实现)
  • 快速随机访问:通过数组下标实现O(1)时间复杂度的元素访问
  • 线程不安全:简易实现不考虑多线程同步问题
  • 泛型支持:通过Object数组存储和类型转换实现泛型特性
  • 空间回收:删除元素时主动置null帮助GC回收

完整实现还应包含size()、isEmpty()、contains()等常用方法,此处展示的是核心逻辑框架。实际JDK中的ArrayList还包含序列化支持、批量操作优化等更复杂的实现。

http://www.jsqmd.com/news/541460/

相关文章:

  • AI辅助开发新体验:让快马AI帮你深度处理六花直装版本更新中的技术任务
  • 智能日历管理:OpenClaw+GLM-4.7-Flash自动安排会议
  • Qwerty Learner 数据持久化架构深度解析:IndexedDB 异步存储方案技术实现
  • Keil MDK-ARM工程配置与优化实践指南
  • TrafficMonitor插件完全指南:三步打造个性化系统监控中心
  • Arduino轻量级哈希表UnorderedMap实战指南
  • 树莓派C语言工程建立
  • 计算机毕业设计springboot羽毛球俱乐部管理系统设计与实现 基于SpringBoot的羽毛球运动场馆预约与会员服务平台开发 羽毛球爱好者社区与场地资源智能调度系统的设计与实现
  • LeetCode-031:下一个排列,从右往左找“转折点”,再反转后缀
  • debian 更新内核后,nvidia 驱动突然不见了,处理
  • 基于springboot的志愿者招募管理系统
  • springboot框架的的网上烘焙蛋糕商城销售系统-vue
  • 终极免费CAJ转PDF工具:caj2pdf完整使用指南
  • LeetCode-287:寻找重复数,把数组看成“指针图”,用 Floyd 判环
  • 零门槛AI视频增强:3阶段提速3倍的Squirrel-RIFE实战指南
  • 二分查找/二分答案
  • 蒙纳什大学发现多模态推理模型的“不确定性陷阱“
  • 2026钢模板租赁优质厂家精选指南 - 优质品牌商家
  • 基于主从博弈的主动配电网阻塞管理探索
  • The Dark Art of Low-Light Enhancement: Why Retinex Models Don’t Need Handcrafted Priors Anymore
  • OpenClaw自动化测试:Qwen3-32B批量执行LeetCode题目
  • STM32开发中的C语言高效编程技巧
  • 禾赛与华为拿下七成市场,激光雷达“抢单大战”谁在掉队?
  • LeetCode-041:缺失的第一个正数,把数组当哈希表,原地放回“该在的位置”
  • 使用小龙虾来操作猿编程的遥控车
  • 02.Linux常用文件操作命令
  • Python MCP协议实战指南:深度解析RFC-8888兼容实现与5大核心中间件集成(附GitHub Star 1.2k模板库)
  • 魔兽争霸III终极优化指南:WarcraftHelper插件完全使用教程
  • BMH23M001 24位Σ-Δ ADC模块技术解析与高精度测量实践
  • 【华为OD机试真题】伐木工 · 木材切割收益最大化问题(C语言)