- 核心概念与定义
- 主要区别对比 (一张图看懂)
- 详细特性分析
- 代码示例
- 如何选择:何时用数组,何时用
ArrayList?
核心概念与定义
数组
数组是 Java 中一种最基础的数据结构,它是一个固定长度的、用来存储同一种类型数据的容器。

- 特点:
- 长度固定:一旦创建,其大小就不能再改变。
- 类型固定:只能存储声明时指定的数据类型(包括其子类)。
- 底层连续内存:所有元素在内存中是连续存储的,这使得通过索引访问元素非常快(时间复杂度 O(1))。
ArrayList
ArrayList 是 Java 集合框架 (java.util.ArrayList) 中最常用的一个类,它内部是基于动态数组实现的,可以看作是一个长度可变的数组。
- 特点:
- 长度可变:可以根据需要动态地增加或减少元素。
- 只能存储对象:
ArrayList只能存储对象类型,不能存储基本数据类型(如int,char),如果要存储基本数据类型,需要使用它们的包装类(如Integer,Character)。 - 底层是数组:虽然它的大小可变,但其内部实现仍然依赖于一个数组,当元素数量超过当前数组容量时,它会创建一个更大的新数组,并将旧数组的元素复制过去,这是一个相对耗时的操作(摊销时间复杂度 O(1))。
主要区别对比 (一张图看懂)
| 特性 | 数组 | ArrayList |
|---|---|---|
| 长度 | 固定,创建时必须指定 | 可变,可以动态增长和缩小 |
| 数据类型 | 可以是基本数据类型 (如 int[]),也可以是对象 |
只能存储对象类型,基本类型需用包装类 (如 ArrayList<Integer>) |
| 性能 | 访问 (get/set) 极快,增删慢(需移动元素)。 | 访问 (get/set) 很快,增删在末尾时快,在中间/开头时慢(同数组),扩容时较慢。 |
| 功能/方法 | 功能非常有限,只有 length 属性和一些基本操作 |
功能非常丰富,提供 add(), remove(), size(), get(), sort() 等大量便捷方法 |
| 声明和初始化 | int[] arr = new int[5]; 或 int[] arr = {1, 2, 3}; |
ArrayList<Integer> list = new ArrayList<>(); |
| 泛型支持 | 不支持泛型,类型在编译时通过检查 | 支持泛型,提供编译时类型安全检查 |
详细特性分析
数组
- 优点:
- 内存占用小:没有额外的对象开销(
ArrayList自身的一些属性)。 - 访问速度快:由于内存连续,可以通过索引直接计算出内存地址,访问元素是 O(1) 操作。
- 内存占用小:没有额外的对象开销(
- 缺点:
- 长度固定:如果不知道需要多少元素,很难确定一个合适的长度,太浪费空间,太小又不够用。
- 功能单一:没有内置的方法来方便地排序、搜索、添加或删除元素,所有操作都需要自己手动实现,非常繁琐。
ArrayList
- 优点:
- 长度灵活:可以动态添加或删除元素,非常方便,无需关心底层数组的大小。
- 功能强大:提供了大量标准库方法,如
add(),remove(),contains(),sort()等,极大地提高了开发效率。 - 支持泛型:可以在编译时检查类型,避免了
ClassCastException,代码更安全、更清晰。
- 缺点:
- 性能开销:由于是对象,每个元素都会有一个额外的引用开销,在频繁扩容时,会有性能损耗(复制旧数组到新数组)。
- 不能存基本类型:必须使用包装类,而包装类是对象,会涉及到自动装箱/拆箱,会有一定的性能开销。
代码示例
数组操作
public class ArrayExample {
public static void main(String[] args) {
// 1. 声明和初始化
int[] numbers = new int[3]; // 创建一个长度为3的整型数组
numbers[0] = 10;
numbers[1] = 20;
numbers[2] = 30;
// 也可以这样初始化
String[] names = {"Alice", "Bob", "Charlie"};
// 2. 获取长度
System.out.println("Numbers array length: " + numbers.length); // 输出 3
// 3. 访问元素
System.out.println("First number: " + numbers[0]); // 输出 10
// 4. 遍历数组
System.out.println("--- Traversing names array ---");
for (int i = 0; i < names.length; i++) {
System.out.println(names[i]);
}
// 5. 数组的缺点:长度固定,无法直接添加元素
// numbers[3] = 40; // 这行代码会抛出 ArrayIndexOutOfBoundsException 异常
}
}
ArrayList 操作
import java.util.ArrayList;
import java.util.Collections;
public class ArrayListExample {
public static void main(String[] args) {
// 1. 声明和初始化 (注意:必须使用包装类 Integer)
ArrayList<Integer> numberList = new ArrayList<>();
// 2. 添加元素 (长度可变)
numberList.add(10);
numberList.add(20);
numberList.add(30);
System.out.println("Initial list: " + numberList); // 输出 [10, 20, 30]
// 3. 获取大小
System.out.println("List size: " + numberList.size()); // 输出 3
// 4. 在指定位置插入元素
numberList.add(1, 15); // 在索引1的位置插入15
System.out.println("After inserting 15: " + numberList); // 输出 [10, 15, 20, 30]
// 5. 访问元素
System.out.println("Element at index 2: " + numberList.get(2)); // 输出 20
// 6. 删除元素
numberList.remove(0); // 删除索引为0的元素 (10)
System.out.println("After removing element at index 0: " + numberList); // 输出 [15, 20, 30]
numberList.remove(Integer.valueOf(20)); // 删除值为20的元素
System.out.println("After removing value 20: " + numberList); // 输出 [15, 30]
// 7. 遍历 ArrayList (多种方式)
System.out.println("--- Traversing with for-each loop ---");
for (Integer num : numberList) {
System.out.println(num);
}
// 8. 使用 Collections 工具类进行排序
numberList.add(5);
numberList.add(25);
System.out.println("Before sorting: " + numberList); // 输出 [15, 30, 5, 25]
Collections.sort(numberList);
System.out.println("After sorting: " + numberList); // 输出 [5, 15, 25, 30]
}
}
如何选择:何时用数组,何时用 ArrayList?
这是一个非常常见的面试问题,答案取决于你的具体需求。
优先选择 ArrayList 的情况 (90% 的情况):
- 当你不知道需要存储多少个元素时:这是
ArrayList最核心的优势。 - 当你需要频繁地添加或删除元素时:
ArrayList提供了非常方便的 API。 - 当你需要使用丰富的集合操作时:如排序、查找、清空等。
- 当你需要代码的简洁性和可读性时:
ArrayList的泛型和丰富方法让代码更现代化、更易维护。
在绝大多数业务开发场景下,默认选择 ArrayList,它更灵活、更安全、更方便。
优先选择数组 的情况 (10% 的情况):
- 当你确定数据量大小且固定不变时:表示一周的七天、一年的十二个月,数组更节省内存。
- 在追求极致性能的高频计算场景中:在游戏引擎、科学计算或图像处理中,对内存布局和访问速度有极高要求,数组的连续内存访问模式对 CPU 缓存更友好。
- 作为
ArrayList或其他集合的底层存储时:ArrayList内部就是用数组来实现的。 - 在需要与 JNI (Java Native Interface) 交互时:因为 C/C++ 代码对原生数组操作更直接。
| 数组 | ArrayList | |
|---|---|---|
| 一句话概括 | 一个固定大小的原始数据容器 | 一个可动态扩展的对象集合 |
| 核心优势 | 速度快,内存占用小 | 灵活方便,功能强大 |
| 核心劣势 | 不灵活,功能有限 | 有性能开销,不能存基本类型 |
| 使用场景 | 性能敏感、大小固定的场景 | 绝大多数日常开发场景 |
ArrayList 是数组的“超级升级版”,它保留了数组快速访问的优点,同时解决了其长度固定、功能单一的缺点,在日常开发中,除非你有非常特殊的需求,否则都应该优先使用 ArrayList。


