add()方法加元素:add(E)追加末尾,add(int,E)在指定位置插入并后移后续元素;空ArrayList调用add(1,"x")会因索引越界抛IndexOutOfBoundsException,合法索引范围是0≤index≤size。

add() 方法怎么加元素,加在哪
add() 有两个常用重载:一个是 add(E element),直接追加到末尾;另一个是 add(int index, E element),在指定位置插入。后者会把原位置及之后的元素全部后移一位。
常见错误是传入越界 index——比如对空 ArrayList 调用 add(1, "x"),会抛出 IndexOutOfBoundsException;合法索引范围是 0 (注意上限等于当前大小,允许插到最后)。
- 想追加就用
add(element),最安全 - 想插中间必须确认
index不超size(),别误以为最大只能到size()-1 - 频繁在头部或中间
add(index, ...)会导致大量元素位移,性能差;真有这种需求,考虑LinkedList
remove() 方法删元素时的两个陷阱
remove() 也有两个重载,但签名容易混淆:remove(int index) 删指定下标,remove(Object o) 删第一个匹配值。编译器靠参数类型自动选择,但如果你传一个 Integer,它可能走错路。
典型翻车场景:本想删值 remove(5),结果删了第 5 个元素(下标为 5),因为 5 被当成 int 而非 Integer;反过来,remove((Integer)5) 才走对象删除逻辑。
- 删下标:明确用
remove(3)或remove((int)3) - 删值:强制转型或用
remove(new Integer(5)),更稳妥的是list.removeIf(e -> Objects.equals(e, 5)) - 删完记得检查返回值——
remove(int)返回被删元素,remove(Object)返回boolean表示是否删成功
边遍历边 add/remove 会出 ConcurrentModificationException
直接在 for-each 或普通 Iterator 遍历时调用 add() 或 remove(),几乎必抛 ConcurrentModificationException。这不是线程问题,而是 ArrayList 的 fail-fast 机制在起作用。
- 安全删法:用
Iterator.remove()(仅限删除),例如it.remove() - 安全增法:遍历完再批量
addAll(),或改用ListIterator并调用它的add() - 真要边扫边改,先收集待操作索引/元素,遍历完再统一处理,避免迭代器状态混乱
add() 和 remove() 对内存和扩容的影响
ArrayList 底层是数组,add() 可能触发扩容:当容量不足时,新容量通常是旧容量的 1.5 倍(JDK 17+ 是 1.5 倍,早期版本略有差异)。扩容要新建数组、复制数据,开销不小。
remove() 不缩容,删再多元素,底层数组长度也不变——除非手动调 trimToSize()。这意味着反复增删后,size() 很小但 capacity 很大,浪费内存。
- 预估大小时用
new ArrayList(initialCapacity),减少扩容次数 - 长期只减不增的场景,删完调一次
trimToSize() -
remove()后如果紧接着add(),旧空间大概率复用,不必急着trimToSize()
实际写的时候,多数时候就是 add() 往尾部塞、remove() 删值或删下标,但那几个隐式类型选择、迭代器冲突、扩容缩容的点,一不留神就卡住半天。










