17-手写ArrayList:从0实现动态数组

发布时间:2026/7/18 0:22:03

17-手写ArrayList:从0实现动态数组
手写ArrayList从0实现动态数组彻底搞懂自动扩容开篇你真的理解ArrayList吗日常开发中ArrayList是最常用的集合。但面试官追问ArrayList底层是怎么扩容的为什么默认容量是10删元素时为什么要System.arraycopy很多人就答不上来。最好的学习方式就是手写一遍。本文从0实现一个简易ArrayList把扩容、增删改查、迭代器原理全部讲透。一、ArrayList的本质ArrayList底层就是一个Object数组加上一个size计数器记录有效元素个数。Object[] elementData int size数组一旦创建长度就固定ArrayList的动态只是个假象容量不够时新建更大数组把旧数据拷贝过去。二、手写ArrayList骨架2.1 基本结构publicclassMyArrayListE{privateObject[]elementData;// 存元素的数组privateintsize;// 有效元素个数publicMyArrayList(){this(10);// 默认容量10}publicMyArrayList(intinitialCapacity){elementDatanewObject[initialCapacity];}publicintsize(){returnsize;}}【面试高频】JDK1.7中ArrayList初始化时就创建长度10的数组JDK1.8优化为延迟初始化首次add时才创建。三、add方法与扩容原理3.1 add实现publicbooleanadd(Ee){// 1. 检查是否需要扩容ensureCapacity(size1);// 2. 存入元素size1elementData[size]e;returntrue;}privatevoidensureCapacity(intminCapacity){if(minCapacityelementData.length){grow(minCapacity);}}3.2 扩容核心逻辑privatevoidgrow(intminCapacity){intoldCapacityelementData.length;// 新容量 旧容量 * 1.5intnewCapacityoldCapacity(oldCapacity1);// 处理新容量不够的边界情况if(newCapacityminCapacity){newCapacityminCapacity;}// 创建新数组拷贝旧数据elementDataArrays.copyOf(elementData,newCapacity);}【面试高频】ArrayList扩容是1.5倍计算方式是oldCapacity (oldCapacity 1)。用位运算比除法更高效。3.3 为什么是1.5倍太小如1.2倍频繁扩容频繁创建数组性能差太大如2倍浪费内存空间1.5倍是空间和时间的折中选择【面试陷阱】Vector扩容是2倍因为Vector是线程安全的扩容开销相对锁来说占比小。四、get与set方法4.1 get实现publicEget(intindex){rangeCheck(index);// 越界检查return(E)elementData[index];}privatevoidrangeCheck(intindex){if(indexsize||index0){thrownewIndexOutOfBoundsException(Index: index, Size: size);}}4.2 set实现publicEset(intindex,Eelement){rangeCheck(index);EoldValue(E)elementData[index];elementData[index]element;returnoldValue;}set返回旧值这是个容易忽略的细节。五、remove方法与数组拷贝5.1 按索引删除publicEremove(intindex){rangeCheck(index);EoldValue(E)elementData[index];// 计算需要移动的元素个数intnumMovedsize-index-1;if(numMoved0){System.arraycopy(elementData,index1,elementData,index,numMoved);}// 最后一位置null帮助GCelementData[--size]null;returnoldValue;}5.2 为什么要System.arraycopy删除中间元素后后面所有元素要整体前移一位。手动写循环效率低System.arraycopy是native方法直接操作内存性能最高。删除索引2的元素 [A, B, C, D, E, null] size5 ↓ [A, B, D, E, null, null] size4【面试高频】ArrayList的删除是O(n)操作因为要移动元素。这也是LinkedList存在的价值。5.3 按元素删除publicbooleanremove(Objecto){if(onull){for(inti0;isize;i){if(elementData[i]null){fastRemove(i);returntrue;}}}else{for(inti0;isize;i){if(o.equals(elementData[i])){fastRemove(i);returntrue;}}}returnfalse;}【面试陷阱】按元素删除用equals比较不是。所以自定义类必须重写equals。六、迭代器原理6.1 为什么不用for循环遍历删除for(inti0;ilist.size();i){if(list.get(i).equals(a)){list.remove(i);// 会导致索引错乱}}删除后size变化后面元素前移导致跳过下一个元素。6.2 手写迭代器publicclassMyIteratorE{privateObject[]elementData;privateintsize;privateintcursor;// 下一个要返回的索引publicMyIterator(Object[]elementData,intsize){this.elementDataelementData;this.sizesize;}publicbooleanhasNext(){returncursorsize;}SuppressWarnings(unchecked)publicEnext(){return(E)elementData[cursor];}}6.3 fail-fast机制JDK的ArrayList迭代器有modCount检查遍历过程中如果用list.remove修改结构会抛ConcurrentModificationException。正确做法是用迭代器的remove方法它会同步更新modCount。七、完整测试publicclassTest{publicstaticvoidmain(String[]args){MyArrayListStringlistnewMyArrayList();// 测试add和扩容for(inti0;i15;i){list.add(元素i);}System.out.println(size: list.size());// 15// 测试getSystem.out.println(list.get(0));// 元素0System.out.println(list.get(14));// 元素14// 测试setlist.set(0,新元素);System.out.println(list.get(0));// 新元素// 测试removelist.remove(0);System.out.println(list.get(0));// 元素1System.out.println(size: list.size());// 14}}八、与JDK源码的对比维度我的实现JDK实现默认容量1010延迟初始化扩容倍数1.51.5删除方式arraycopyarraycopy序列化无重写writeObject/readObjectfail-fast无modCount机制并发修改无保护抛CME异常【面试高频】ArrayList用transient修饰elementData自定义序列化只写有效元素节省空间。九、性能对比操作ArrayListLinkedList随机访问O(1)O(n)头部插入O(n)O(1)尾部插入平均O(1)O(1)中间插入O(n)O(n)删除O(n)O(n)内存占用紧凑每个节点额外存前后指针【面试陷阱】不要以为LinkedList插入删除一定比ArrayList快。中间位置插入LinkedList也要先遍历到位置时间复杂度也是O(n)。十、开发踩坑实录坑 1边遍历边删除for(Strings:list){if(s.equals(a)){list.remove(s);// ConcurrentModificationException}}正确做法用迭代器remove或Java 8的removeIf。坑 2subList修改影响原ListListIntegersublist.subList(1,3);sub.set(0,100);// 原list也被修改原因subList返回的是视图不是副本。坑 3Arrays.asList不能addListIntegerlistArrays.asList(1,2,3);list.add(4);// UnsupportedOperationException原因返回的是Arrays内部类不是真正的ArrayList。十一、面试速记卡11.1 核心知识点知识点答案底层结构Object数组默认容量10JDK8延迟初始化扩容倍数1.5倍扩容方式Arrays.copyOf删除元素System.arraycopy前移是否线程安全否随机访问O(1)序列化transient修饰数组自定义序列化11.2 高频面试题ArrayList底层是什么默认容量是多少ArrayList扩容机制是怎样的为什么是1.5倍ArrayList和Vector有什么区别ArrayList和LinkedList有什么区别ArrayList的remove是怎么实现的为什么遍历时删除会抛ConcurrentModificationExceptionArrayList用transient修饰数组的原因ArrayList在多线程下会有什么问题11.3 口诀底层Object数组默认容量是10 扩容一点五倍Arrays.copyOf来拷贝 删除arraycopy前移最后一位置null 随机访问O一插入删除O n transient修饰数组自定义序列化省空间十二、小结手写一遍ArrayList你对扩容、删除、迭代器原理都会有深刻理解。面试时被问到ArrayList能从源码角度回答比背八股强一百倍。记住ArrayList的核心数组1.5倍扩容System.arraycopy。这三个点搞懂ArrayList的面试题基本都能应对。

相关新闻

JDK详解:从入门到精通

JDK详解:从入门到精通

2026/7/18 0:22:03

一.什么是jdkJDK也就是Java开发工具包, 它身为整个JAVA的核心, 涵盖了Java运行环境, 也就是Java , 还有一堆诸如javac/java/jdb等的Java工具, 以及Java基础的类库, 也就是Java API包括rt.jar。JDK也就是java开发工具包, 于其安装目录之下存在五个文件夹, 以及一些描述文件, 还有…

2026 中国十大一站式家族综合服务商榜单发布 柏越集团(PARICH GROUP LIMITED)凭全牌照标准化综合服务强势入选

2026 中国十大一站式家族综合服务商榜单发布 柏越集团(PARICH GROUP LIMITED)凭全牌照标准化综合服务强势入选

2026/7/18 0:22:03

近日,亚太高净值家族服务行业权威测评机构发布 2026 年度大湾区一站式家族综合服务商 TOP10 榜单,围绕完整跨境金融资质、全链条标准化服务、全球落地交付能力、高净值客户口碑、资产安全合规体系五大核心维度综合评审,聚焦全球身份规划、海内…

【半导体百科】光刻工艺参数优化:实战案例与Python实现

【半导体百科】光刻工艺参数优化:实战案例与Python实现

2026/7/18 0:12:02

一、问题背景光刻是集成电路制造中最核心的工艺环节之一,其工艺窗口的宽窄直接决定芯片的良率和性能。在实际生产中,曝光能量、焦距、显影时间和光刻胶厚度等参数的细微偏差,都可能导致图形转移失败,进而造成晶圆报废。在28nm及以…

STM32 GPIO配置与LED控制实战指南

STM32 GPIO配置与LED控制实战指南

2026/7/18 1:42:09

1. 项目概述刚接触STM32的新手们,GPIO控制绝对是你们要跨过的第一道门槛。作为最基础的外设接口,GPIO就像单片机的"手脚",通过它我们才能与外部世界进行交互。今天我就以最经典的LED控制为例,带大家彻底搞懂STM32的GPIO…

人形机器人武术表演背后的核心技术:动态平衡与全身运动控制

人形机器人武术表演背后的核心技术:动态平衡与全身运动控制

2026/7/18 1:42:09

1. 项目概述:当人形机器人“舞”起中国功夫最近,一段人形机器人表演中国功夫,为农历新年助兴的视频在网络上引发了不小的关注。作为一名长期关注机器人技术发展的从业者,我第一眼看到这个标题时,内心是既兴奋又带着一丝…

ExpressJS与现代Node.js框架对比:性能与迁移指南

ExpressJS与现代Node.js框架对比:性能与迁移指南

2026/7/18 1:42:09

1. 为什么2021年该重新评估ExpressJS十年前我刚接触Node.js后端开发时,ExpressJS几乎是唯一的选择。就像老工匠手中的瑞士军刀,它用中间件机制和简洁的路由API征服了整个社区。但时至今日,当我看到新项目还在默认选用Express时,总…

Android悬浮窗开发全指南:从原理到多版本适配

Android悬浮窗开发全指南:从原理到多版本适配

2026/7/18 1:42:09

1. Android悬浮窗技术背景与核心挑战悬浮窗作为Android系统特色功能,本质上是通过WindowManager将View附加到系统窗口层级中。这种技术允许应用在全局范围内显示内容,不受Activity生命周期限制,常见于录屏工具、聊天头像、游戏辅助等场景。在…

Laravel异常处理机制详解与最佳实践

Laravel异常处理机制详解与最佳实践

2026/7/18 1:42:09

1. Laravel异常处理机制概述在Laravel开发中,异常处理是保证应用健壮性的重要环节。传统的try-catch方式虽然有效,但会导致代码重复且难以维护。Laravel提供了一套完整的异常处理机制,让我们能够以更优雅的方式处理各种错误场景。Laravel的异…

具身智能基础技术路线:破解感知-动作耦合与实时控制断层

具身智能基础技术路线:破解感知-动作耦合与实时控制断层

2026/7/18 1:32:08

1. 具身智能不是“会动的AI”,而是重新定义“智能”的起点很多人第一次听到“具身智能”这个词,下意识反应是:“哦,就是给大模型装上机器人身体?”——这恰恰踩进了最典型的认知陷阱。我带过三支不同方向的具身团队&am…

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践

2026/7/17 10:50:47

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator XUnity.AutoTranslator作为Unity游戏社区中最成熟的文本翻译解决方…

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持

2026/7/17 17:34:09

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持 【免费下载链接】raspberrypi-kernel It provides openEuler kernel source for Raspberry Pi 项目地址: https://gitcode.com/openeuler/raspberrypi-kernel 前往项目官网免费下载&…

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧

2026/7/16 14:18:17

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧 【免费下载链接】integration-test The repo contains test suits for system integration test 项目地址: https://gitcode.com/openeuler/integration-test 前往项目官网免费下载:…

从模糊意图到可执行指令:Claude PRD中Prompt Engineering与需求颗粒度的5级映射法则

从模糊意图到可执行指令:Claude PRD中Prompt Engineering与需求颗粒度的5级映射法则

2026/7/18 0:02:02

更多请点击: https://kaifayun.com 第一章:从模糊意图到可执行指令:Claude PRD中Prompt Engineering与需求颗粒度的5级映射法则 在Claude驱动的产品需求文档(PRD)生成实践中,原始业务意图往往以自然语言片…

Cursor配置生成失效?3大隐藏陷阱+4行修复代码,资深工程师连夜整理的紧急补救清单

Cursor配置生成失效?3大隐藏陷阱+4行修复代码,资深工程师连夜整理的紧急补救清单

2026/7/18 0:02:02

更多请点击: https://codechina.net 第一章:Cursor配置生成失效?3大隐藏陷阱4行修复代码,资深工程师连夜整理的紧急补救清单 Cursor 配置生成突然失效,是近期高频报障场景。表面看是 cursor.config.json 未更新或 LSP…

某智驾大牛创业

某智驾大牛创业

2026/7/18 0:02:02

作者:钟声编辑:Mark出品:红色星际头图:智能驾驶图片据悉,国内某头部智驾公司端到端模型技术大牛Z投身创业,并且已经拿到融资。Z不仅是该头部公司内部最年轻的对标阿里P10级别技术负责⼈,更是业内…