ArrayList知识点

一、ArrayList 核心定义

ArrayList 是 Java 集合框架中 List 接口的动态数组实现 (基于数组扩容),位于 java.util 包下,默认实现了 RandomAccess(支持随机访问)、Cloneable(可克隆)、Serializable(可序列化)接口,线程不安全。

二、底层原理

  1. 存储结构 :底层基于Object \[\] 数组 (elementData)存储元素,JDK 7 中数组默认初始容量为 10(空参构造直接初始化 new Object[10]),JDK 8 做了优化(空参构造初始化空数组 DEFAULTCAPACITY_EMPTY_ELEMENTDATA,首次添加元素时才扩容为 10,节省内存)。
  2. 扩容机制 (核心面试点):
    • 触发条件:当添加元素时,数组容量不足(size == elementData.length);
    • 扩容流程:
      1. 计算新容量:默认扩容为原容量的 1.5 倍(oldCapacity + (oldCapacity >> 1));
      2. 数组拷贝:通过 Arrays.copyOf() 将原数组元素拷贝到新数组(底层是 System.arraycopy () 本地方法);
    • 手动扩容:可通过 ensureCapacity(int minCapacity) 提前指定容量,减少多次扩容的性能损耗。

三、核心特性

表格

特性 说明
随机访问 支持通过索引快速访问(时间复杂度 O (1)),因为数组内存地址连续
增删效率 尾部增删:O (1)(无扩容时);非尾部增删:O (n)(需移动元素)
线程安全 线程不安全(未加同步锁),多线程场景需使用 Collections.synchronizedList() 或 CopyOnWriteArrayList
允许 null 值 可存储 null 元素(可通过 indexOf (null) 查找 null 位置)
有序性 元素按插入顺序存储,索引从 0 开始
容量可动态调整 区别于普通数组(固定长度),ArrayList 可通过扩容自动调整容量

四、常用核心方法

java

运行

复制代码
// 1. 初始化
List<String> list1 = new ArrayList<>(); // JDK8 空数组,首次添加扩容为10
List<String> list2 = new ArrayList<>(20); // 指定初始容量20
List<String> list3 = new ArrayList<>(Arrays.asList("a", "b")); // 基于集合初始化

// 2. 增删改查
list1.add("java"); // 尾部添加(O(1))
list1.add(1, "python"); // 指定索引添加(O(n))
list1.remove(0); // 按索引删除(O(n))
list1.remove("java"); // 按元素删除(需遍历,O(n))
list1.set(0, "c++"); // 修改指定索引元素(O(1))
String elem = list1.get(0); // 随机访问(O(1))
int index = list1.indexOf("python"); // 查找元素索引(O(n))

// 3. 扩容相关
list1.ensureCapacity(100); // 手动指定最小容量,避免多次扩容
list1.trimToSize(); // 缩容:将数组容量调整为当前元素个数(释放多余内存)

// 4. 遍历(推荐方式)
// 方式1:for循环(随机访问效率高)
for (int i = 0; i < list1.size(); i++) {
    System.out.println(list1.get(i));
}
// 方式2:增强for循环(底层是迭代器)
for (String s : list1) {
    System.out.println(s);
}
// 方式3:迭代器(支持遍历中删除元素)
Iterator<String> it = list1.iterator();
while (it.hasNext()) {
    String s = it.next();
    if (s.equals("python")) {
        it.remove(); // 正确删除方式(避免ConcurrentModificationException)
    }
}

五、面试高频易错点

  1. 遍历中删除元素的坑 :

    • 错误:增强 for 循环中直接调用 list.remove() → 抛出 ConcurrentModificationException(快速失败机制,modCount != expectedModCount);
    • 正确:使用迭代器的 it.remove() 或普通 for 循环倒序删除。
  2. ArrayList vs LinkedList 区别 (高频对比):

    表格

    维度 ArrayList LinkedList
    底层结构 数组 双向链表(Node 节点)
    随机访问 O (1)(快) O (n)(慢,需遍历)
    增删效率 非尾部 O (n) 首尾增删 O (1),中间 O (n)
    内存占用 连续内存,有扩容冗余 每个节点存储前后指针,内存开销大
    适用场景 频繁查询、少量增删 频繁增删、少量查询
  3. JDK 7 vs JDK 8 初始化差异 :

    • JDK 7:空参构造 → 直接创建长度为 10 的数组;
    • JDK 8:空参构造 → 初始化空数组,首次 add 元素时才扩容为 10(懒加载)。
  4. subList () 陷阱 :

    • list.subList(from, to) 返回的是原数组的视图(非新数组),修改子列表会同步修改原列表;
    • 子列表持有原列表引用,原列表扩容后(数组地址变化),子列表操作会抛异常。

六、使用场景

  • 适合频繁查询、少量增删的场景(如数据展示、排行榜);
  • 不适合高频增删(非尾部) 或多线程并发修改的场景(后者优先用 CopyOnWriteArrayList)。

总结

ArrayList 核心关键点:

  1. 底层是动态扩容的 Object 数组,默认扩容 1.5 倍,随机访问效率高、非尾部增删效率低;
  2. 线程不安全,遍历删除需用迭代器,避免 ConcurrentModificationException;
  3. JDK 8 优化了初始化逻辑(懒加载),与 LinkedList 核心区别在底层结构和访问 / 增删效率。
相关推荐
小羊没烦恼!3 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
俊昭喜喜里3 天前
java中的继承和多态的区别
java
小羊没烦恼!3 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
rockmelodies3 天前
# Windows Server2008 R2 Standard(SP1镜像U盘)重置本地管理员密码【完整详细步骤】
windows·密码破解
譕痕3 天前
JSONObject与JSONArray封装数据格式区别
java·json
胡写代码3 天前
别再前后端各写一套表单校验了
java·后端
小鱼能吃糖3 天前
缺陷修复总览 · mall电商项目:5类缺陷,1个病根,4个业务域
java·电商
此时不提桶,更待何时3 天前
01-06-A-JVM排查实战详解
java·jvm
伞伞悦读3 天前
【第38期】Python 模块与包详解:import、from、模块搜索路径、包结构和 __init__
开发语言·python
vipxieliang3 天前
ValidX 在 DDD 领域驱动设计中的实践
java·spring boot