ArrayList核心逻辑

ArrayList 是Java 集合框架中最常用的动态数组实现类。它在 java.util.ArrayList 包下,继承自 AbstractList,实现了 List 接口。

核心特点:底层基于数组实现,容量可以自动扩容,支持快速随机访问。

一、核心特点

  • 动态扩容 :初始容量默认是 10,存满后会自动扩容为原来的 1.5 倍;
  • 有序可重复 :元素存入顺序和取出顺序一致,允许存储重复元素、null 值;
  • 随机访问快:通过索引访问元素的时间复杂度是 O (1),效率极高;
  • 增删慢:中间插入 / 删除元素需要移动后续元素,时间复杂度 O (n);
  • 非线程安全 :多线程环境下不建议使用(推荐 CopyOnWriteArrayList)。

二、基础使用

1. 创建ArrayList

java 复制代码
import java.util.ArrayList;

// 推荐:指定泛型(约束存储的元素类型)
ArrayList<String> list = new ArrayList<>(); 

2. 常用方法

java 复制代码
// 1. 添加元素
list.add("Java");
list.add("Python");
list.add(1, "C++"); // 在索引 1 位置插入元素

// 2. 获取元素
String s = list.get(0); // 获取索引 0 的元素

// 3. 修改元素
list.set(1, "Go"); // 把索引 1 的元素改为 Go

// 4. 删除元素
list.remove(0); // 根据索引删除
list.remove("Java"); // 根据元素删除

// 5. 其他常用方法
list.size(); // 获取元素个数
list.isEmpty(); // 判断是否为空
list.contains("Python"); // 判断是否包含某个元素
list.clear(); // 清空集合

3. 遍历 ArrayList

java 复制代码
// 方式1:for 循环(通过索引,推荐随机访问)
for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}

// 方式2:增强 for 循环(最常用)
for (String str : list) {
    System.out.println(str);
}

// 方式3:迭代器
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    System.out.println(it.next());
}

三、ArrayList底层原理

1. 底层数据结构

Object 数组 transient Object[] elementData;

2. 初始容量

  • JDK 1.7:默认初始容量 10;
  • JDK 1.8+:懒加载,第一次添加元素时才初始化容量为 10;

3. 扩容机制

当元素个数达到数组容量时,自动扩容:新容量 = 旧容量 + 旧容量 >> 1(等价于 1.5 倍);扩容后会用 Arrays.copyOf() 复制原数组元素。

四、如何保证 ArrayList 的线程安全

ArrayList 本身是非线程安全的,多线程同时读写会出现数据错乱、并发修改异常**(ConcurrentModificationException)**。

Java 提供了 3 种标准方案保证线程安全:

1. Collections.synchronizedList ()(简单包装)

这是最快实现线程安全的方式,对 ArrayList 加锁包装。

java 复制代码
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

// 把普通 ArrayList 变成线程安全
List<String> safeList = Collections.synchronizedList(new ArrayList<>());

特点:

  • 简单、一行代码搞定
  • 粗粒度锁,并发性能一般
  • 遍历时仍需要手动加锁

遍历注意: 必须手动加锁,否则仍会报错。

java 复制代码
synchronized (safeList) {  // 必须加锁
    for (String s : safeList) {
        System.out.println(s);
    }
}

2. 使用 Vector(古老、不推荐)

Vector 是 Java 早期的线程安全集合,所有方法都加 synchronized。

特点:

  • 线程安全,但性能差
  • 几乎被淘汰,不要在新项目使用

3. CopyOnWriteArrayList(高并发首选)

Java 官方推荐的线程安全 List ,属于 java.util.concurrent 并发包。

java 复制代码
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

// 最推荐的线程安全 List
List<String> safeList = new CopyOnWriteArrayList<>();

核心原理:

  • 写时复制:添加 / 删除时,复制一个新数组操作
  • 读不加锁,写加锁
  • 适合:读多写少 的高并发场景

优点:

  • 完全线程安全
  • 遍历不需要加锁
  • 高并发下性能远好于 synchronizedList

4. 三种方案对比

方案 线程安全 性能 适用场景
ArrayList ❌ 不安全 最好 单线程
Collections.synchronizedList ✅ 安全 一般 简单并发、低并发
Vector ✅ 安全 最差 老项目、不推荐
CopyOnWriteArrayList ✅ 安全 读高并发优秀 读多写少、高并发

五、ArrayList 与 普通数组 的区别

特性 普通数组 ArrayList
容量 固定不可变 动态自动扩容
存储类型 基本类型 + 引用类型 只能存引用类型
功能 简单存取 提供丰富的增删改查方法
使用场景 固定长度数据 长度不确定、频繁操作

注意:ArrayList 不能存 int、char 等基本类型,只能存包装类 Integer、Character。

六、使用注意事项

1. 指定初始容量

如果能预估元素数量,创建时指定容量,减少扩容开销。

2. 线程不安全

多线程下不要直接使用,可使用:

  • 日常开发、低并发使用 Collections.synchronizedList()
  • 高并发、读多写少使用 CopyOnWriteArrayList

3. 遍历删除问题

在 ArrayList 遍历过程中删除元素,只有迭代器(Iterator)的删除方式是完全安全、不会报错的。

直接用 for/增强for 删除都会出问题:

  • 普通 for:漏删、下标越界
  • 增强 for:ConcurrentModificationException 并发修改异常

用迭代器删除ArrayList元素关键点:

  • 必须用 it.remove() ,不能用 list.remove()
  • 必须先调用 it.next() ,再调用 remove()
  • 不会抛异常,不会漏删,最安全

不能用 list.remove ()的原因:

  • 遍历过程中,直接调用集合的删除方法会修改集合结构,导致迭代器检测到 "被修改",直接抛出异常。

迭代器删除原理:

  • ① 迭代器会记录集合修改次数
  • ② 只有迭代器自己的 remove () 会同步修改次数,不会触发异常
  • ③ 外部调用 list.remove() 会导致修改次数不匹配 → 报错
相关推荐
夏天的清晨7 分钟前
C++入门学习
开发语言·c++·学习
代码山河9 分钟前
Java的前世今生:从Oak语言到Java 23的发展史
java·学习·架构·教程·面向对象·项目
新鲜势力呀10 分钟前
PHP 文件上传系统实战:从上传卡顿到分片上传 + 秒传 + 云存储架构完整优化方案
开发语言·架构·php
vx_Biye_Design10 分钟前
springboot角色扮演服务平台65161-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·python·spring·课程设计
李游Leo11 分钟前
HarmonyOS 7 QuickDock 闪控窗开发实录 02:floatView × floatingBall:形态切换、位置恢复与单一状态源【鸿蒙心迹】
java·华为·harmonyos
企业数字化笔记12 分钟前
视频局部合成怎么做得自然?掩膜修复、边缘羽化、时序稳定与背景替换
java·javascript·音视频
仍然.18 分钟前
Redis---主从复制
java·数据库·redis
vx_Biye_Design22 分钟前
springboot咖啡厅顾客点单管理系统12080-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·spring·课程设计·express
QQ_216962909625 分钟前
基于微信小程序的智能膳食分析系统
java·大数据·spring boot·微信小程序·小程序·旅游
程序员老陆26 分钟前
从语法糖到类型系统:深度拆解 C++ Lambda 与可调用对象的“血缘关系”
开发语言·c++·程序设计