Java存储数据:数组与集合

Java 存储数据:数组 vs 集合(全面对比与使用指南)

在 Java 中,存储一组数据最常用的两种方式就是数组(Array)集合(Collection)
它们各有优势,理解它们的区别和适用场景,是 Java 开发者的基础功底。

1. 核心对比表(建议背下来)

维度数组(Array)集合(Collection / List / Set / Map)胜出场景
长度/大小固定长度(创建时确定,不可变)动态长度(可自动扩容/缩容)集合胜
数据类型支持基本类型和引用类型(int[]、String[])只能存储引用类型(包装类或对象),不支持基本类型数组胜(基本类型场景)
底层实现连续内存块多种实现(ArrayList 也是数组,LinkedList 是链表)
访问效率get/set O(1) 极快ArrayList O(1),LinkedList O(n)数组 / ArrayList 胜
插入/删除效率中间插入/删除需要移动元素 O(n)ArrayList 中间 O(n),LinkedList O(1)LinkedList 胜(频繁插入删除)
是否可变长度不可变,元素可变长度可变,元素可变集合胜
是否线程安全非安全大部分非安全(少数如 CopyOnWriteArrayList 安全)视具体实现
是否支持泛型支持泛型(Java 5+)支持泛型(推荐使用)
内存开销较低(只有数据本身)较高(有额外结构、对象头、包装类)数组胜
功能丰富度几乎无内置方法非常丰富(contains、remove、sort、subList 等)集合胜
典型实现类int[]、String[]、Object[]ArrayList、LinkedList、HashSet、HashMap 等

一句话总结:

  • 数组固定长度、高性能、基本类型友好,适合数据量确定且追求极致性能的场景
  • 集合动态、可扩展、功能强大,适合绝大多数业务开发场景

2. 什么时候用数组?什么时候用集合?

强烈推荐使用集合的场景(90%+ 情况)

  • 数据长度不确定或会变化
  • 需要频繁增删改查
  • 需要判断元素是否存在(contains)
  • 需要排序、去重、子列表等高级操作
  • 使用泛型提高类型安全
  • 团队协作开发(代码可读性更高)

推荐使用数组的场景(少数但重要)

  • 数据长度固定且已知(如一周7天、12个月)
  • 需要存储基本类型且在意内存和性能(int[]、double[])
  • 高性能计算场景(科学计算、游戏开发、实时系统)
  • 与底层 API 交互(如 IO 操作、JNI、反射)
  • 极致内存敏感场景(如海量数据处理)

3. 代码对比示例

// --------------------- 数组 ---------------------
int[] scores = new int[5];           // 固定长度
scores[0] = 85;
scores[1] = 92;
// scores[5] = 100;                  // 越界!ArrayIndexOutOfBoundsException

// 遍历
for (int i = 0; i < scores.length; i++) {
    System.out.println(scores[i]);
}

// --------------------- 集合(ArrayList) ---------------------
import java.util.ArrayList;
import java.util.List;

List<Integer> scoreList = new ArrayList<>();
scoreList.add(85);
scoreList.add(92);
scoreList.add(78);
scoreList.add(100);                 // 长度自动增长

// 插入到中间
scoreList.add(1, 99);               // 自动后移元素

// 删除
scoreList.remove(2);                // 删除索引2的元素

// 判断是否存在
if (scoreList.contains(100)) {
    System.out.println("有100分");
}

// 更方便的遍历
for (Integer score : scoreList) {
    System.out.println(score);
}

// 排序
scoreList.sort(Integer::compareTo);

4. 常见误区与避坑

  1. 误区1:用数组存对象却频繁扩容
   // 错误示范:频繁创建新数组 + 复制
   String[] arr = new String[10];
   // ... 满了再 new String[20] + System.arraycopy

正确:直接用 ArrayList<String>

  1. 误区2:基本类型用集合导致大量装箱
   List<Integer> list = new ArrayList<>();  // 装箱开销

优化方案(大数据量时):

  • 用第三方库:Trove、fastutil(intArrayList、IntArrayList)
  • 或自己维护 int[]
  1. 误区3:数组当作集合用,却忘记长度固定
   String[] names = new String[100];
   int count = 0;
   // 手动维护 count,很容易出错
  1. 误区4:多线程下直接用 ArrayList
    正确做法
  • Collections.synchronizedList(new ArrayList<>())
  • CopyOnWriteArrayList(读多写少)
  • Vector(不推荐)
  • ConcurrentLinkedQueue(队列场景)

5. 快速选择指南

问自己这几个问题:

  1. 长度是否固定且已知? → → 用数组
  2. 需要存储基本类型且性能敏感? → → 用数组
  3. 需要动态增删、查找、排序等操作? → → 用集合
  4. 是业务系统、Web、企业开发? → 99% 用集合(ArrayList 为主)
  5. 是高性能计算、游戏、嵌入式、大数据底层? → 考虑数组

总结口诀

“不确定长度、要方便操作,优先集合;长度固定、追求极致性能,用数组。”

大多数 Java 开发者日常 90%+ 的列表场景用的是 ArrayList,但理解数组与集合的底层差异,能让你在性能优化、面试、底层框架阅读时更有优势。

如果你想深入某个具体点,比如:

  • ArrayList 扩容机制详解
  • LinkedList vs ArrayList 真实性能对比
  • 基本类型集合的第三方优化方案
  • 多线程安全的 List 选择

随时告诉我,我可以继续展开讲解!

文章已创建 4580

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部