ArrayList底层是动态Object数组,初始容量默认10(JDK14+懒初始化),扩容为1.5倍,泛型擦除后存Object、需包装类,增删中间元素需移动数据,size为实际元素数,capacity为数组长度。

ArrayList 底层就是用一个普通的 Object 数组来存数据的,不是链表,也不是哈希表,就是一个数组——只不过这个数组的长度可以变化,所以叫“动态数组”。
初始容量和扩容机制
创建 ArrayList 时,默认会分配一个长度为 10 的 Object[] 数组(JDK 14+ 后改为懒初始化,首次 add 才创建);你也可以传入初始容量,比如 new ArrayList(20),它就会直接创建长度为 20 的数组。
当数组装不下新元素时(即 size == elementData.length),ArrayList 会触发扩容:新容量 = 旧容量 × 1.5(即 oldCapacity + (oldCapacity >> 1)),然后用 Arrays.copyOf() 把老数组内容复制到新数组里。
- 扩容是耗时操作,涉及内存分配和数组拷贝,频繁 add 可能影响性能
- 如果事先知道大概要存多少元素,建议指定初始容量,避免多次扩容
数组怎么存不同类型的数据?
因为泛型在编译期会被擦除(type erasure),ArrayList
立即学习“Java免费学习笔记(深入)”;
你是 TypeScript 项目架构专家,专注于脚手架搭建生产就绪的 Node.js 和前端应用。生成包含现代工具链(pnpm、Vite、Next.js)、类型
例如:ArrayList
底层执行的是:elementData[0] = (Object)"hello";
这也是为什么 ArrayList 不能存基本类型(如 int),必须用包装类(Integer)——因为 Object 数组无法直接存 int 值。
删除和插入怎么影响数组?
ArrayList 的增删操作都在数组上进行,但中间插入或删除会导致部分元素移动:
- add(index, e):从 index 开始所有元素右移一位,再把 e 放进 index 位置
- remove(index):从 index+1 开始所有元素左移一位,最后把末尾位置设为 null(帮助 GC)
- 这些移动操作时间复杂度是 O(n),所以随机位置增删不如 LinkedList 快
size 和 capacity 的区别
size 是当前实际存了多少个元素(list.size() 返回值);capacity 是底层数组的长度(不可直接获取,但可通过反射或估算得知)。两者常不相等——数组可能有空位,这是为了减少扩容频率。
你可以用 trimToSize() 把数组长度缩成当前 size,释放多余空间;也可以用 ensureCapacity(minCapacity) 主动预扩容。

















