ArrayList 核心知识点速记

一、ArrayList 基础定义

ArrayList 是 Java 集合框架中 List 接口 的可调整大小数组实现,位于 java.util 包下,是开发中最常用的动态数组(区别于普通数组的固定长度)。

核心特点

  1. 底层基于数组实现,支持快速随机访问(通过索引获取元素)。
  2. 容量可自动扩容(默认初始容量 10,扩容时按 1.5 倍增长)。
  3. 允许存储重复元素null 值
  4. 非线程安全(多线程环境下需使用 VectorCopyOnWriteArrayList)。
  5. 增删操作(尤其是中间位置)效率较低(需移动元素)。

二、核心 API(常用方法)

表格

方法 功能说明
boolean add(E e) 末尾添加元素,返回是否成功
void add(int index, E element) 指定索引位置插入元素
E get(int index) 获取指定索引的元素
E remove(int index) 删除指定索引的元素,返回被删元素
boolean remove(Object o) 删除第一个匹配的元素,返回是否成功
E set(int index, E element) 修改指定索引的元素,返回原元素
int size() 获取集合中元素的数量
boolean isEmpty() 判断集合是否为空
void clear() 清空集合所有元素
int indexOf(Object o) 获取元素首次出现的索引,不存在返回 - 1
boolean contains(Object o) 判断集合是否包含指定元素

三、使用步骤

  1. 导包import java.util.ArrayList;
  2. 创建对象
    • 无参构造(常用):ArrayList<String> list = new ArrayList<>();
    • 指定初始容量:ArrayList<Integer> list = new ArrayList<>(20);
  3. 调用方法:增删改查核心操作。

基础示例

java

运行

import java.util.ArrayList;

public class ArrayListDemo {
    public static void main(String[] args) {
        // 1. 创建ArrayList对象(存储字符串类型)
        ArrayList<String> foodList = new ArrayList<>();

        // 2. 新增元素
        foodList.add("麻辣小龙虾");
        foodList.add("螺蛳粉");
        foodList.add(1, "炸鸡"); // 索引1位置插入

        // 3. 查询元素
        System.out.println("索引2的元素:" + foodList.get(2)); // 输出:螺蛳粉
        System.out.println("集合大小:" + foodList.size()); // 输出:3

        // 4. 修改元素
        foodList.set(0, "蒜蓉小龙虾");

        // 5. 删除元素
        foodList.remove(1); // 删除索引1的"炸鸡"

        // 6. 遍历元素(增强for循环)
        for (String food : foodList) {
            System.out.println(food); // 输出:蒜蓉小龙虾、螺蛳粉
        }
    }
}

四、遍历方式

  1. 增强 for 循环(推荐,简洁):

    java

    运行

    for (E element : list) {
        // 处理元素
    }
    
  2. 普通 for 循环(需索引操作时使用):

    java

    运行

    for (int i = 0; i < list.size(); i++) {
        E element = list.get(i);
    }
    
  3. 迭代器(Iterator)(删除元素时推荐,避免并发修改异常):

    java

    运行

    Iterator<E> it = list.iterator();
    while (it.hasNext()) {
        E element = it.next();
        if (条件) {
            it.remove(); // 安全删除
        }
    }
    

五、常见应用场景

  1. 存储数量不固定的同类型数据(如外卖菜品列表、用户列表)。
  2. 需要快速查询(按索引),但增删操作较少的场景。
  3. 单线程环境下的动态数据存储(多线程需加锁或换线程安全类)。

六、核心对比(与普通数组)

表格

特性 ArrayList 普通数组
长度 动态扩容 固定长度
方法 丰富的操作方法(add/remove 等) 仅能通过索引访问
存储 仅支持引用数据类型(基本类型需用包装类) 支持基本 / 引用数据类型
效率 随机访问快,增删慢 访问快,增删需手动重构

总结

  1. ArrayList动态数组,解决了普通数组长度固定的问题,核心优势是灵活扩容和丰富的操作方法。
  2. 核心操作围绕增(add)、删(remove)、改(set)、查(get) 展开,遍历优先用增强 for 循环。
  3. 适合查询多、增删少的场景,线程不安全,存储基本类型需使用包装类(如 IntegerString)。

题目一:ArrayList之模仿外卖系统综合案例

一、解题步骤分析

步骤 1:需求拆解与类设计

  • 明确需求:实现菜品上架菜品信息浏览功能,结合面向对象与 ArrayList 集合完成。
  • 抽象实体:将 “菜品” 抽象为Food类,封装菜品的核心数据(名称、原价、优惠价、描述信息)。
  • 划分职责:设计FoodManager类负责业务逻辑(上架、浏览、交互界面),FoodTest类作为程序入口启动系统。

步骤 2:编写菜品类(Food)

  • 定义私有成员变量:name(菜品名)、originalPrice(原价)、discountPrice(优惠价)、info(描述信息)。
  • 提供无参 / 带参构造方法,方便创建对象。
  • 生成 Getter/Setter 方法,实现对私有变量的安全访问。
  • 重写toString()方法,格式化输出菜品信息,便于浏览查看。

步骤 3:编写菜品管理类(FoodManager)

  • 初始化集合:使用ArrayList<Food>存储所有上架菜品,实现动态数据管理。
  • 实现交互界面:showMenu()方法展示功能菜单,通过循环 + switch 接收用户操作选择。
  • 实现上架功能:addFood()方法读取用户输入,创建Food对象并添加到集合。
  • 实现浏览功能:showAllFoods()方法遍历集合,打印所有菜品信息,空集合时给出提示。

步骤 4:编写测试类(FoodTest)

  • 创建FoodManager对象,调用showMenu()方法启动系统,完成功能测试。

二、完整代码示例

代码一:编写菜品类(Food)

package com.sy.food;

/**
* 菜品类
*/

public class Food {
    private String name; // 菜品名称
    private double oldPrice; // 原价格
    private double vipPrice; // 优惠价格
    private String info; // 描述信息

    public Food() {
    }
    public Food(String name, double oldPrice, double vipPrice, String info) {
        this.name = name;
        this.oldPrice = oldPrice;
        this.vipPrice = vipPrice;
        this.info = info;
    }
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getOldPrice() {
        return oldPrice;
    }

    public void setOldPrice(double oldPrice) {
        this.oldPrice = oldPrice;
    }

    public double getVipPrice() {
        return vipPrice;
    }

    public void setVipPrice(double vipPrice) {
        this.vipPrice = vipPrice;
    }

    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }

    @Override
    public String toString() {
        return "Food{" +
                "name='" + name + '\'' +
                ", oldPrice=" + oldPrice +
                ", vipPrice=" + vipPrice +
                ", info='" + info + '\'' +
                '}';
    }
}
 

代码二:写菜品管理类(FoodManager)

package com.sy.food;

import java.util.ArrayList;
import java.util.Objects;
import java.util.Scanner;

/**
 * 菜品管理类(添加菜品 浏览菜品  功能菜单)
 */

public class FoodManage {

    // 菜品管理(多种) ==> 集合  集合中储存的是菜品
    ArrayList<Food> list = new ArrayList();

    // 扫描器(键盘录入)
    Scanner sc = new Scanner(System.in);

    // 添加菜品方法
    public void addFood(){
        System.out.println("---------菜品上架---------");
        Food food = new Food();
        System.out.println("请输入您上架的菜品名称: ");
        String name = sc.next();
        food.setName(name);


        System.out.println("请输入您上架的菜品价格: ");
        double oldPrice = sc.nextDouble();
        food.setOldPrice(oldPrice);

        System.out.println("请输入您上架的菜品优惠价格: ");
        double vipPrice = sc.nextDouble();
        food.setVipPrice(vipPrice);


        System.out.println("请输入您上架的菜品描述信息: ");
        String info = sc.next();
        food.setInfo(info);

        list.add(food);

        System.out.println("恭喜您, 上架成功...");
    }

    // 浏览菜品方法
    public void queryFood(){
        System.out.println("----当前菜品信息描述如下----");
        for (int i = 0; i < list.size(); i++) {
            Food food = list.get(i);
            System.out.println("菜品名称: " + food.getName());
            System.out.println("菜品原价格: " + food.getOldPrice());
            System.out.println("菜品优惠价格: " + food.getVipPrice());
            System.out.println("菜品描述信息: " + food.getInfo());
            System.out.println("----------------------------------------");
        }
    }

    // 操作界面方法
    public void start(){
        while (true){
            // 功能菜单
            System.out.println("=======欢迎进入外卖系统=======");
            System.out.println("1. 上架菜品(add)");
            System.out.println("2. 浏览菜品(query)");
            System.out.println("3. 退出系统(exit)");
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入菜单命令: ");
            String command = sc.next();

            switch (command){
                case "add":
                    this.addFood();
                    break;
                case "query":
                    this.queryFood();
                    break;
                case "exit":
                    return;
                default:
                    System.out.println("您输入的命令有误...");
            }
        }
    }
}

代码三:编写测试类(FoodTest)

package com.sy.food;

import java.util.Scanner;

/**
 * 菜品测试类
 */

public class FoodTest {
    public static void main(String[] args) {
        // 创建操作类
        FoodManage foodManage = new FoodManage();
        foodManage.start();
    }
}

三、知识点总结

1. 面向对象编程核心

  • 封装:将菜品属性私有化,通过 Getter/Setter 控制访问,保证数据安全性和完整性。
  • 类与对象Food是模板,描述菜品的共同特征;每个具体菜品是Food的实例对象。
  • 方法设计:按功能拆分方法(上架、浏览、展示菜单),提高代码可读性和复用性。

2. ArrayList 集合应用

  • 动态存储:相比数组,ArrayList可自动扩容,适合存储数量不确定的菜品对象。
  • 核心操作
    • add(E e):添加菜品对象(上架功能)。
    • isEmpty():判断集合是否为空(浏览前校验)。
    • 增强 for 循环:遍历集合,批量打印菜品信息。
  • 泛型使用ArrayList<Food>指定存储类型,避免类型转换异常,提高代码安全性。

3. Java 基础语法

  • 输入输出:使用Scanner接收用户输入,System.out.println展示信息。
  • 流程控制while(true)实现循环菜单,switch-case处理用户选择。
  • 方法重载:重写toString()方法,自定义对象的字符串表现形式。

题目二:基于 ArrayList 的购物车批量删除枸杞商品案例

一、解题思维分析

步骤 1:需求理解与问题拆解

  • 核心需求:从购物车商品列表中,批量删除所有包含 “枸杞” 的商品,并验证删除结果。
  • 数据载体:使用ArrayList<String>存储购物车商品名称,模拟后台数据。
  • 关键难点:遍历集合时直接删除元素会引发ConcurrentModificationException(并发修改异常),需要选择安全的删除方式。

步骤 2:数据初始化

  • 创建ArrayList<String>对象,将商品依次添加到集合中:

    java

    运行

    ArrayList<String> cart = new ArrayList<>();
    cart.add("Java入门");
    cart.add("宁夏枸杞");
    cart.add("黑枸杞");
    cart.add("人字拖");
    cart.add("特级枸杞");
    cart.add("枸杞子");
    

步骤 3:遍历与筛选删除(核心逻辑)

  • 筛选规则:判断商品名称是否包含 “枸杞” 关键字(str.contains("枸杞"))。
  • 安全遍历方式选择
    1. 迭代器(Iterator)遍历(推荐,避免并发修改异常):
    • 通过iterator()获取迭代器,使用hasNext()判断是否有下一个元素。
    • next()获取当前元素,若包含 “枸杞” 则调用iterator.remove()安全删除。
    1. 倒序 for 循环遍历(备选,避免索引越界):
    • 从集合末尾向前遍历(for (int i = list.size()-1; i >= 0; i--)),若满足条件则调用remove(i)删除。

步骤 4:结果验证

  • 打印删除后的集合,确认所有含 “枸杞” 的商品已被移除,仅保留不含 “枸杞” 的商品。

二、完整代码示例

package com.sy.arraylist;

import java.util.ArrayList;

public class ArrayListTest04 {
    public static void main(String[] args) {
        /**
         *  购物车案例: (优化版本二)
         *    分析:
         *        1.创建一个集合表示购物车  购物车存储商品名称(String)
         *        2.将商品添加到购物车中
         *        3.遍历出购物车中的每一件商品, 只要商品名称中包含"枸杞"都要删除(批量删除)
         */
        // 1.创建一个集合表示购物车  购物车存储商品名称(String)
        ArrayList<String> list = new ArrayList<>();

        // 2.将商品添加到购物车中
        list.add("Java入门");
        list.add("宁夏枸杞");
        list.add("黑枸杞");
        list.add("人字拖");
        list.add("特级枸杞");
        list.add("枸杞子");
        // 打印购物车
        System.out.println(list);

        // 3.遍历出购物车中的每一件商品, 只要商品名称中包含"枸杞"都要删除(批量删除)
        for (int i = list.size() - 1; i > 0; i--) {
            /**
             * [Java入门, 宁夏枸杞, 黑枸杞, 人字拖, 特级枸杞, 枸杞子]
             *     0        1      2      3       4      5
             */
            String str = list.get(i);
            // System.out.println(str);
            // 判断商品中是否包含"枸杞"  删除
            if (str.contains("枸杞")){
                // 删除元素
                list.remove(str);
            }
        }
        // 批量删除后的打印效果
        System.out.println(list);
    }
}

三、知识点总结

1. ArrayList 遍历与删除核心知识

表格

知识点 详细说明
遍历方式 - 增强 for 循环:简洁直观,但遍历中不能删除元素,否则会抛异常。- 普通 for 循环:可操作索引,但正序删除会导致索引前移,漏删元素。- 迭代器(Iterator):安全删除的标准方式,支持遍历过程中删除元素。
contains () 方法 String.contains(CharSequence s):判断字符串是否包含指定子串,用于筛选目标商品。
安全删除技巧 - 迭代器删除:iterator.remove(),是遍历过程中删除元素的唯一安全方式。- 倒序 for 循环:从后往前遍历删除,避免因索引变化导致漏删。
并发修改异常 原因:使用增强 for 循环或普通 for 循环遍历时,直接调用list.remove()会修改集合结构,触发modCountexpectedModCount不一致,抛出异常。

2. 易错点总结

  • ❌ 错误:增强 for 循环中直接调用list.remove(),会触发ConcurrentModificationException
  • ❌ 错误:正序 for 循环删除,会导致后续元素索引前移,造成漏删。
  • ✅ 正确:使用迭代器倒序 for 循环进行删除操作。
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐