文章目录

Java 常用集合:ArrayList 与 HashMap 的使用

发布于 2026-04-05 13:06:55 · 浏览 21 次 · 评论 0 条

Java 常用集合:ArrayList 与 HashMap 的使用

在 Java 开发中,集合是存储和操作数据的基础工具。ArrayListHashMap 是最常用的两种集合类型,几乎出现在每一个 Java 项目中。理解它们的特性和适用场景,能够帮助你写出更高效、更易维护的代码。


一、ArrayList:动态数组

ArrayList 是 Java 中最常用的 List 接口实现类,本质上是一个动态数组。它允许存储重复元素,且保持元素的插入顺序。

1.1 基本特性

特性 说明
数据结构 数组(Object[])
元素有序 是(按插入顺序)
元素唯一 否(允许重复)
随机访问 支持(通过索引,时间复杂度 O(1))
线程安全 否(线程不安全)

1.2 常用操作

创建 ArrayList 并添加元素

import java.util.ArrayList;
import java.util.List;

public class ArrayListExample {
    public static void main(String[] args) {
        // 创建 ArrayList(推荐使用泛型指定类型)
        List<String> fruits = new ArrayList<>();

        // 添加元素
        fruits.add("苹果");
        fruits.add("香蕉");
        fruits.add("橙子");

        System.out.println(fruits); // [苹果, 香蕉, 橙子]
    }
}

根据索引访问和修改元素

// 获取指定索引的元素
String first = fruits.get(0); // "苹果"

// 修改指定索引的元素
fruits.set(1, "葡萄"); // 将索引1的元素改为"葡萄"

// 删除元素(按索引或按对象)
fruits.remove(0);    // 删除索引0的元素
fruits.remove("橙子"); // 删除值为"橙子"的元素

遍历 ArrayList

// 方式1:普通 for 循环
for (int i = 0; i < fruits.size(); i++) {
    System.out.println(fruits.get(i));
}

// 方式2:增强 for 循环(推荐)
for (String fruit : fruits) {
    System.out.println(fruit);
}

// 方式3:Lambda 表达式(Java 8+)
fruits.forEach(fruit -> System.out.println(fruit));

1.3 注意事项

ArrayList 在中间位置插入或删除元素时,需要移动后续所有元素,时间复杂度为 O(n)。如果你的业务场景涉及频繁的中间插入删除操作,考虑使用 LinkedList 替代。


二、HashMap:键值对映射

HashMap 是 Map 接口最常用的实现类,基于哈希表结构实现。它以键值对的形式存储数据,每个键唯一,对应的值可以重复。

2.1 基本特性

特性 说明
数据结构 数组 + 链表/红黑树(JDK 1.8+)
唯一(null 键仅允许一个)
可重复(null 值允许多个)
查找速度 O(1)(平均情况)
线程安全

2.2 常用操作

创建 HashMap 并添加元素

import java.util.HashMap;
import java.util.Map;

public class HashMapExample {
    public static void main(String[] args) {
        // 创建 HashMap
        Map<String, Integer> studentScores = new HashMap<>();

        // 添加键值对
        studentScores.put("张三", 95);
        studentScores.put("李四", 88);
        studentScores.put("王五", 92);

        System.out.println(studentScores); // {张三=95, 李四=88, 王五=92}
    }
}

根据键访问和修改值

// 根据键获取值
Integer score = studentScores.get("张三"); // 95

// 键不存在时返回 null,可设置默认值
Integer defaultScore = studentScores.getOrDefault("赵六", 0); // 0

// 修改键对应的值
studentScores.put("李四", 90); // 更新李四的分数

// 只有键不存在时才添加
studentScores.putIfAbsent("赵六", 85);

删除和检查元素

// 根据键删除
studentScores.remove("王五");

// 检查键是否存在
boolean hasZhangSan = studentScores.containsKey("张三");

// 检查值是否存在
boolean has90 = studentScores.containsValue(90);

// 清空所有元素
studentScores.clear();

遍历 HashMap

// 方式1:遍历键
for (String name : studentScores.keySet()) {
    System.out.println("姓名: " + name);
}

// 方式2:遍历值
for (Integer score : studentScores.values()) {
    System.out.println("分数: " + score);
}

// 方式3:遍历键值对(推荐)
for (Map.Entry<String, Integer> entry : studentScores.entrySet()) {
    System.out.println(entry.getKey() + " 的分数是 " + entry.getValue());
}

// 方式4:Lambda 表达式
studentScores.forEach((name, score) -> 
    System.out.println(name + ": " + score));

2.3 注意事项

HashMap 的性能高度依赖 hashCode() 方法的实现质量。重写 equals() 方法时,必须同时重写 hashCode() 方法,保证相等的对象返回相同的哈希值,否则会导致 HashMap 无法正常工作。


三、核心区别与选择指南

理解 ArrayListHashMap 的本质区别,是正确使用它们的前提。

3.1 核心区别

对比维度 ArrayList HashMap
数据结构 单列集合 键值对映射
访问方式 通过索引访问 通过键访问
查找效率 O(n)(需要遍历) O(1)(平均情况)
插入顺序 保持 不保证(JDK 7 及之前甚至完全无序)

3.2 使用场景选择

选择 ArrayList 的场景

  • 需要按顺序存储和访问元素
  • 主要通过索引进行随机访问
  • 允许存储重复元素
  • 业务逻辑更接近"列表"概念(如待办事项列表、商品列表)

选择 HashMap 的场景

  • 需要通过唯一键快速查找对应值
  • 需要存储键值对形式的数据(如配置信息、缓存数据)
  • 对查询效率有较高要求
  • 需要根据某个唯一标识快速定位数据(如用户 ID -> 用户对象)

四、实战示例:学生信息管理系统

下面通过一个实际场景,展示 ArrayListHashMap 如何配合使用。

import java.util.*;

public class StudentManager {
    // 使用 ArrayList 存储所有学生(保持插入顺序)
    private List<Student> studentList = new ArrayList<>();

    // 使用 HashMap 通过学号快速查找学生
    private Map<String, Student> studentMap = new HashMap<>();

    public void addStudent(String id, String name, int age) {
        Student student = new Student(id, name, age);

        studentList.add(student);
        studentMap.put(id, student);

        System.out.println("添加成功: " + name);
    }

    public Student getStudentById(String id) {
        return studentMap.get(id);
    }

    public List<Student> getAllStudents() {
        return new ArrayList<>(studentList); // 返回副本,避免外部修改
    }

    public void removeStudent(String id) {
        Student removed = studentMap.remove(id);
        if (removed != null) {
            studentList.remove(removed);
            System.out.println("删除成功: " + removed.getName());
        }
    }

    public static void main(String[] args) {
        StudentManager manager = new StudentManager();

        manager.addStudent("S001", "张三", 20);
        manager.addStudent("S002", "李四", 21);
        manager.addStudent("S003", "王五", 19);

        // 快速通过学号查找
        Student s = manager.getStudentById("S002");
        if (s != null) {
            System.out.println("找到学生: " + s.getName());
        }

        // 遍历所有学生
        System.out.println("\n所有学生信息:");
        manager.getAllStudents().forEach(stu -> 
            System.out.println(stu.getId() + " - " + stu.getName()));
    }
}

class Student {
    private String id;
    private String name;
    private int age;

    public Student(String id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public String getId() { return id; }
    public String getName() { return name; }
    public int getAge() { return age; }
}

这个示例充分发挥了两种集合的优势:ArrayList 维护了学生的添加顺序,便于按序展示;HashMap 提供了 O(1) 的查找速度,便于快速定位。


五、进阶技巧

5.1 初始化集合

// 简洁的初始化方式(Java 9+)
List<String> list = List.of("a", "b", "c");
Map<String, Integer> map = Map.of("a", 1, "b", 2);

// 双大括号初始化(了解即可,不推荐生产使用)
List<String> list2 = new ArrayList<String>() {{
    add("a");
    add("b");
}};

5.2 集合转数组/数组转集合

List<String> list = Arrays.asList("a", "b", "c");

// 集合转数组
String[] array = list.toArray(new String[0]);

// 数组转集合
Integer[] nums = {1, 2, 3};
List<Integer> numList = Arrays.asList(nums);

5.3 线程安全的集合

在多线程环境下,ArrayListHashMap 是不安全的。可使用以下替代方案:

import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ConcurrentHashMap;

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

// 线程安全的 Map
Map<String, Integer> safeMap = new ConcurrentHashMap<>();

六、性能调优建议

使用集合时注意以下性能要点:

  1. 指定初始容量ArrayListHashMap 扩容有性能开销。创建时根据预估大小指定初始容量,减少扩容次数。
// 预估需要存储1000个元素
List<String> list = new ArrayList<>(1000);
Map<String, Object> map = new HashMap<>(1000, 0.8f);
  1. 选择合适的负载因子HashMap 默认负载因子 0.75 是时间和空间成本的平衡点。对于追求内存效率的场景,可适当降低。

  2. 避免在循环中频繁调用 size():对于 ArrayList,将 size() 缓存到局部变量,减少方法调用开销。

// 低效
for (int i = 0; i < list.size(); i++) { ... }

// 高效
int size = list.size();
for (int i = 0; i < size; i++) { ... }

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文