- 什么是数组?
- 什么是
ArrayList? ArrayList与数组的核心区别- 代码示例:如何使用数组和
ArrayList - 何时使用数组,何时使用
ArrayList?
什么是数组?
数组是 Java 中最基本的一种数据结构,你可以把它想象成一个固定大小的容器,用来存放相同类型的元素。

核心特点:
- 固定大小:数组一旦被创建,其大小(能存放多少个元素)就不能改变,如果你需要添加更多元素,就必须创建一个新数组,并把旧数组的内容复制过去。
- 类型相同:一个数组里只能存放一种数据类型(全是
int,或全是String)。 - 索引访问:通过索引(从 0 开始)来访问和修改元素,速度非常快。
如何声明和初始化一个数组:
// 1. 声明一个 int 类型的数组,名为 myArray int[] myArray; // 2. 创建一个可以存放 5 个 int 元素的空间 myArray = new int[5]; // 也可以一步完成 String[] names = new String[3]; // 创建一个可以存放 3 个 String 的数组 // 3. 赋值 myArray[0] = 10; myArray[1] = 20; myArray[2] = 30; myArray[3] = 40; myArray[4] = 50; // 4. 访问元素 int firstElement = myArray[0]; // firstElement 的值是 10
什么是 ArrayList?
ArrayList 是 Java 集合框架 (java.util) 中的一部分,你可以把它想象成一个动态的、可自动扩容的数组,它内部实际上就是用数组来实现的,但为你封装好了所有复杂的操作。
核心特点:

- 动态大小:
ArrayList的大小可以随时改变,当你添加的元素超过了当前容量时,它会自动在内部创建一个更大的数组,并将所有元素复制过去,这个过程对用户是透明的。 - 可以存放对象:
ArrayList只能存放对象类型,不能存放基本数据类型(如int,char等),但你可以使用它们的包装类(如Integer,Character)。 - 丰富的 API:提供了很多有用的方法,如
add(),get(),remove(),size()等,使用非常方便。
如何声明和使用一个 ArrayList:
import java.util.ArrayList; // 别忘了导入包!
// 1. 创建一个可以存放 String 对象的 ArrayList
ArrayList<String> namesList = new ArrayList<>();
// 2. 添加元素 (add 方法)
namesList.add("Alice");
namesList.add("Bob");
namesList.add("Charlie");
// 3. 在指定位置插入元素
namesList.add(1, "David"); // 在索引 1 的位置插入 "David"
// 4. 获取元素 (get 方法)
String secondName = namesList.get(1); // secondName 的值是 "David"
// 5. 获取大小 (size 方法)
int size = namesList.size(); // size 的值是 4
// 6. 删除元素
namesList.remove(0); // 删除索引 0 的元素 "Alice"
namesList.remove("Bob"); // 删除值为 "Bob" 的元素
// 7. 遍历 ArrayList
for (String name : namesList) {
System.out.println(name);
}
ArrayList 与数组的核心区别
| 特性 | 数组 | ArrayList |
|---|---|---|
| 大小 | 固定,创建后不能改变。 | 动态,可以随时添加或删除元素,自动扩容/缩容。 |
| 数据类型 | 可以是基本数据类型 (int[]),也可以是对象 (String[])。 |
只能是对象类型,存放基本类型时需使用其包装类 (ArrayList<Integer>)。 |
| 性能 | 访问速度快 (O(1)),增删元素慢(因为涉及移动元素和创建新数组)。 |
访问速度稍慢(因为有自动拆装箱的潜在开销,但也是 O(1)),增删元素更方便,性能也较好。 |
| 功能/方法 | 功能非常有限,只有一个 length 属性。 |
提供了非常丰富的方法,如 add(), remove(), size(), contains() 等。 |
| 语法 | 语法更简洁,直接使用 [] 访问。 |
语法稍显冗长,需要声明泛型类型(如 <String>)。 |
| 内存 | 内存是连续分配的,效率高。 | 有一定的额外内存开销,因为需要维护内部数组的容量和大小。 |
代码示例:一个简单的对比
假设我们要存储一个班级里学生的名字,并添加一个新同学。
使用数组:
public class ArrayExample {
public static void main(String[] args) {
// 1. 创建一个固定大小的数组
String[] students = new String[3];
students[0] = "张三";
students[1] = "李四";
students[2] = "王五";
System.out.println("原始数组: " + java.util.Arrays.toString(students));
// 2. 添加一个新同学 "赵六"
// 数组大小固定,无法直接添加!必须创建一个新数组。
String[] newStudents = new String[students.length + 1];
// 复制旧数组元素到新数组
System.arraycopy(students, 0, newStudents, 0, students.length);
// 添加新元素
newStudents[newStudents.length - 1] = "赵六";
students = newStudents; // 让原数组引用指向新数组
System.out.println("添加后的数组: " + java.util.Arrays.toString(students));
}
}
使用 ArrayList:
import java.util.ArrayList;
public class ArrayListExample {
public static void main(String[] args) {
// 1. 创建一个 ArrayList
ArrayList<String> students = new ArrayList<>();
students.add("张三");
students.add("李四");
students.add("王五");
System.out.println("原始 ArrayList: " + students);
// 2. 添加一个新同学 "赵六"
// 非常简单!
students.add("赵六");
System.out.println("添加后的 ArrayList: " + students);
}
}
从上面的例子可以清晰地看出,ArrayList 在处理动态数据时是多么方便。
何时使用数组,何时使用 ArrayList?
这是一个非常常见且重要的面试问题,以下是简单的判断准则:
优先使用 ArrayList 的情况:
- 当你不知道需要存储多少个元素时,这是最常见的情况,
ArrayList的动态扩容特性完美解决了这个问题。 - 当你需要频繁地添加或删除元素时。
ArrayList提供了简单高效的方法。 - 当你需要使用集合框架提供的强大功能时,
contains()检查元素是否存在,remove()删除特定元素等。 - 在绝大多数日常业务开发中,
ArrayList是默认选择,因为它更灵活、更安全。
考虑使用数组 的情况:
- 当你确定数据量的大小永远不会改变时,表示一年的12个月,一周的7天,使用数组更高效,也更节省内存。
- 当你追求极致的性能时,特别是在处理大量数据且主要操作是随机访问(通过索引读取)时,数组的访问速度理论上比
ArrayList快一点点,因为少了方法调用的开销。 - 当你需要与 Java 的某些底层API交互时,这些API要求参数必须是数组类型(
main方法的String[] args)。 - 在多维数组场景下,如果维度固定,使用原生数组(如
int[][])可能比ArrayList<ArrayList<Integer>>更直观。
| 数组 | ArrayList |
|
|---|---|---|
| 一句话总结 | 一个静态的、固定大小的容器。 | 一个动态的、可自动扩容的容器。 |
| 学习建议 | 理解其基本概念和局限性。 | 作为日常开发的首选,熟练掌握其API。 |
ArrayList 是对数组的强大封装和升级,对于绝大多数 Java 开发场景,你都应该优先使用 ArrayList,只有在少数特定情况下(如数据量固定、追求极致性能),才需要直接使用原始数组,理解它们之间的区别和联系,是成为一名合格 Java 程序员的重要一步。
