数据结构-ArrayList

在 Java 集合框架中,ArrayList 是 List 接口最常用的实现类之一,因其查询效率高、使用灵活的特点,广泛应用于日常开发。本文将从 ArrayList 的核心特点、常用方法、遍历方式到使用注意事项,进行系统性梳理,帮助快速复习并掌握其核心用法。

一、ArrayList 核心特点

ArrayList 本质是动态数组(底层基于数组实现),相比普通数组,它能自动扩容以存储更多元素,同时保留了数组 "按索引访问快" 的优势,具体特点如下:

  1. 存储结构 :底层基于数组,元素在内存中连续存储,通过索引(index,从 0 开始)快速定位元素。
  2. 查询高效 :获取指定索引元素(get(int index))的时间复杂度为 O(1),适合频繁查询的场景。
  3. 增删低效
    • 尾部添加元素(add(Object e))效率较高(无扩容时为 O (1));
    • 中间 / 头部增删元素(add(int index, E e)remove(int index))需移动后续元素,时间复杂度为 O(n),不适合频繁增删的场景。
  4. 线程不安全 :非同步设计,多线程环境下直接使用可能出现数据安全问题(如需线程安全,可使用 Collections.synchronizedList(new ArrayList<>()) 或替代类 CopyOnWriteArrayList)。
  5. 支持泛型 :可通过泛型(如 <String><Integer>)限定存储元素的类型,避免类型转换异常,提升代码安全性。
  6. 自动扩容 :初始容量默认 10,当元素数量超过当前容量时,会自动扩容为原来的 1.5 倍 (通过 Arrays.copyOf() 复制原数组实现)。

二、ArrayList 常用方法

ArrayList 提供了丰富的方法用于操作元素,以下是开发中最常用的方法,均附完整示例代码,直接复制即可运行。

1. 基础操作:添加、获取、删除

(1)添加元素
  • add(E e):向集合尾部添加元素;
  • add(int index, E e):向集合指定索引位置添加元素(原位置及后续元素后移)。
java 复制代码
import java.util.ArrayList;

public class ArrayListAddDemo {
    public static void main(String[] args) {
        // 泛型限定:集合仅存储 String 类型元素
        ArrayList<String> list = new ArrayList<>();
        
        // 1. 尾部添加元素
        list.add("Java");
        list.add("Python");
        System.out.println("尾部添加后:" + list); // 输出:[Java, Python]
        
        // 2. 指定索引添加(索引 1)
        list.add(1, "Golang");
        System.out.println("指定索引添加后:" + list); // 输出:[Java, Golang, Python]
    }
}
(2)获取元素与集合大小
  • get(int index):获取指定索引的元素(索引从 0 开始,越界会抛 IndexOutOfBoundsException);
  • size():返回集合中元素的实际个数(区别于数组的 "容量")。
java 复制代码
public class ArrayListGetSizeDemo {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("北京");
        list.add("上海");
        list.add("广州");
        
        // 获取索引 1 的元素
        String city = list.get(1);
        System.out.println("索引 1 的元素:" + city); // 输出:上海
        
        // 获取集合大小
        int size = list.size();
        System.out.println("集合元素个数:" + size); // 输出:3
    }
}
(3)删除元素
  • remove(int index):删除指定索引的元素,返回被删除的元素,后续元素前移;
  • remove(Object o):删除集合中第一次出现 的指定元素,返回 booleantrue 表示删除成功,false 表示元素不存在)。
java 复制代码
public class ArrayListRemoveDemo {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("苹果");
        list.add("香蕉");
        list.add("香蕉");
        list.add("橙子");
        
        // 1. 按索引删除(删除索引 1 的元素)
        String removedByIndex = list.remove(1);
        System.out.println("按索引删除的元素:" + removedByIndex); // 输出:香蕉
        System.out.println("删除后集合:" + list); // 输出:[苹果, 香蕉, 橙子]
        
        // 2. 按元素删除(删除第一次出现的"香蕉")
        boolean isRemoved = list.remove("香蕉");
        System.out.println("是否删除成功:" + isRemoved); // 输出:true
        System.out.println("最终集合:" + list); // 输出:[苹果, 橙子]
    }
}

2. 进阶操作:修改、判断、清空

(1)修改元素
  • set(int index, E e):用新元素替换指定索引的旧元素,返回被替换的旧元素
java 复制代码
public class ArrayListSetDemo {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(10);
        list.add(20);
        list.add(30);
        
        // 替换索引 1 的元素(20 → 25)
        Integer oldVal = list.set(1, 25);
        System.out.println("被替换的旧值:" + oldVal); // 输出:20
        System.out.println("修改后集合:" + list); // 输出:[10, 25, 30]
    }
}
(2)判断元素与集合空否
  • contains(Object o):判断集合是否包含指定元素,返回 boolean
  • isEmpty():判断集合是否为空(元素个数为 0),返回 boolean
java 复制代码
public class ArrayListJudgeDemo {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("猫");
        list.add("狗");
        
        // 1. 判断是否包含"狗"
        boolean hasDog = list.contains("狗");
        System.out.println("是否包含狗:" + hasDog); // 输出:true
        
        // 2. 判断集合是否为空
        boolean isEmpty = list.isEmpty();
        System.out.println("集合是否为空:" + isEmpty); // 输出:false
        
        // 清空集合后再判断
        list.clear();
        System.out.println("清空后集合是否为空:" + list.isEmpty()); // 输出:true
    }
}
(3)清空集合
  • clear():删除集合中所有元素,集合变为空(但对象本身仍存在)。
java 复制代码
public class ArrayListClearDemo {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("A");
        list.add("B");
        System.out.println("清空前:" + list); // 输出:[A, B]
        
        // 清空集合
        list.clear();
        System.out.println("清空后:" + list); // 输出:[]
        System.out.println("清空后大小:" + list.size()); // 输出:0
    }
}

3. ArrayList 三种遍历方式

遍历是集合的核心操作,ArrayList 支持三种常用遍历方式,需根据场景选择:

(1)普通 for 循环(适合需索引的场景)

通过 size() 获取长度,get(int index) 获取指定索引元素,可手动控制遍历顺序。

java 复制代码
public class ArrayListForDemo {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("周一");
        list.add("周二");
        list.add("周三");
        
        // 普通 for 循环遍历
        for (int i = 0; i < list.size(); i++) {
            System.out.println("索引 " + i + ":" + list.get(i));
        }
        // 输出:
        // 索引 0:周一
        // 索引 1:周二
        // 索引 2:周三
    }
}
(2)增强 for 循环(foreach,简洁高效)

无需关注索引,直接遍历每个元素,代码简洁,是日常开发的首选。

java 复制代码
public class ArrayListForEachDemo {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("Spring");
        list.add("MyBatis");
        list.add("SpringBoot");
        
        // 增强 for 循环遍历
        for (String framework : list) {
            System.out.println("框架:" + framework);
        }
        // 输出:
        // 框架:Spring
        // 框架:MyBatis
        // 框架:SpringBoot
    }
}
(3)迭代器(Iterator,支持遍历中删除元素)

通过 iterator() 获取迭代器,用 hasNext() 判断是否有下一个元素,next() 获取元素。注意 :遍历中删除元素需用 iterator.remove(),而非 list.remove(),否则会抛 ConcurrentModificationException

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

public class ArrayListIteratorDemo {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("红色");
        list.add("绿色");
        list.add("蓝色");
        
        // 迭代器遍历
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            String color = iterator.next();
            // 遍历中删除"绿色"
            if ("绿色".equals(color)) {
                iterator.remove(); // 必须用迭代器的 remove() 方法
            }
            System.out.println("颜色:" + color);
        }
        System.out.println("删除后集合:" + list); // 输出:[红色, 蓝色]
    }
}

三、ArrayList 使用注意事项

  1. 索引越界问题get(int index)remove(int index) 等方法的索引需在 [0, size()-1] 范围内,否则会抛 IndexOutOfBoundsException,使用前需确认索引合法性。
  2. 泛型与空元素
    • 泛型仅支持引用类型(如 Integer,而非 int);
    • ArrayList 允许存储 null 元素(但不建议,可能导致后续 equals() 判断空指针)。
  3. 线程安全问题 :ArrayList 非线程安全,多线程同时读写时,需通过 Collections.synchronizedList() 包装,或使用线程安全的 CopyOnWriteArrayList
  4. 扩容性能优化 :若已知集合元素数量,创建 ArrayList 时可指定初始容量(如 new ArrayList<>(100)),减少自动扩容次数(扩容需复制数组,消耗性能)。
  5. 与 LinkedList 的区别 :ArrayList 适合查询多、增删少 的场景;LinkedList(链表实现)适合增删多、查询少的场景,需根据业务选择。

四、总结

ArrayList 作为 Java 中最常用的集合类,核心是 "动态数组" 的实现,优势在于快速查询,劣势在于中间增删效率低。掌握其核心方法(添加、获取、删除、修改)和三种遍历方式,结合使用注意事项(索引、线程安全、扩容优化),就能在开发中灵活应用。

相关推荐
小xin过拟合2 小时前
day20 二叉树part7
开发语言·数据结构·c++·笔记·算法
刘 大 望3 小时前
网络编程--TCP/UDP Socket套接字
java·运维·服务器·网络·数据结构·java-ee·intellij-idea
寻星探路3 小时前
数据结构青铜到王者第三话---ArrayList与顺序表(1)
数据结构
今后1233 小时前
【数据结构】顺序表详解
数据结构·顺序表
啟明起鸣3 小时前
【数据结构】B 树——高度近似可”独木成林“的榕树——详细解说与其 C 代码实现
c语言·开发语言·数据结构
nonono3 小时前
数据结构——线性表(链表,力扣中等篇,技巧型)
数据结构·leetcode·链表
hrrrrb3 小时前
【数据结构】栈和队列——队列
数据结构
XMZH030423 小时前
数据结构:单向链表的逆置;双向循环链表;栈,输出栈,销毁栈;顺序表和链表的区别和优缺点;0825
数据结构·链表·
KarrySmile5 小时前
Day8--HOT100--160. 相交链表,206. 反转链表,234. 回文链表,876. 链表的中间结点
数据结构·算法·链表·双指针·快慢指针·hot100·灵艾山茶府