数组

数组是什么

数组就是一排储物柜,每个柜子有个编号(下标),柜子数量在建好的时候就固定了,不能增减

特点:类型相同长度固定下标从0开始

想象一下学校走廊的储物柜:一排10个,编号从0到9,每个柜子只能放同一种东西(比如都放书或都放鞋)

声明和初始化

两种方式:你知道要放什么就直接列出来(静态初始化),只知道要几个柜子就先建空柜子(动态初始化)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Test
public void testArrayInit() {
System.out.println("=== 数组的声明和初始化 ===");

// 方式1:静态初始化 —— 直接告诉Java放什么
int[] scores = {90, 85, 78, 92, 88};
System.out.println("scores长度:" + scores.length); // 5

// 方式1的完整写法(效果一样,上面是简写)
int[] scores2 = new int[]{90, 85, 78, 92, 88};

// 方式2:动态初始化 —— 先建5个空柜子,之后再放东西
int[] ages = new int[5];
// 此时每个元素都是默认值:int默认0,double默认0.0,boolean默认false,引用类型默认null
System.out.println("ages[0] 默认值:" + ages[0]); // 0

ages[0] = 18;
ages[1] = 22;
System.out.println("ages[0] = " + ages[0]); // 18
}
初始化方式 语法 适用场景
静态初始化 int[] arr = {1, 2, 3}; 已知所有元素值
动态初始化 int[] arr = new int[5]; 只知道长度,值后面再填

注意int[] arrint arr[] 都行,但 Java 推荐前者,因为”int[]”整体表示”整型数组”这个类型,更清晰

访问元素和遍历

下标从0开始,最大下标是 length - 1,这跟我们日常从1开始数不一样,刚开始很容易搞错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Test
public void testArrayAccess() {
System.out.println("=== 访问和遍历 ===");

String[] fruits = {"苹果", "香蕉", "橘子", "葡萄"};

// 通过下标访问,下标从0开始
System.out.println("第1个水果:" + fruits[0]); // 苹果
System.out.println("第4个水果:" + fruits[3]); // 葡萄

// 遍历方式1:经典for循环(需要下标的时候用这个)
// 参考 [流程控制](/2026/04/04/流程控制/) 中的for循环
System.out.println("--- for循环遍历 ---");
for (int i = 0; i < fruits.length; i++) {
System.out.println("下标" + i + ":" + fruits[i]);
}

// 遍历方式2:for-each(只需要值、不需要下标时用这个,更简洁)
System.out.println("--- for-each遍历 ---");
for (String fruit : fruits) {
System.out.println(fruit);
}
}
遍历方式 语法 优点 缺点
for循环 for (int i = 0; i < arr.length; i++) 能拿到下标,能修改元素 写起来稍长
for-each for (int x : arr) 简洁,不会越界 拿不到下标,不能修改元素

常见异常:ArrayIndexOutOfBoundsException

数组越界是新手最常踩的坑,就是你去开编号不存在的柜子,Java直接报错给你看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Test
public void testArrayException() {
System.out.println("=== 数组越界异常 ===");

int[] arr = {10, 20, 30}; // 下标只有 0, 1, 2

// 下面这行会抛出 ArrayIndexOutOfBoundsException
// System.out.println(arr[3]); // ❌ 下标3不存在!
// System.out.println(arr[-1]); // ❌ Java不支持负数下标!

// 安全的做法:访问前检查下标范围
int index = 3;
if (index >= 0 && index < arr.length) {
System.out.println(arr[index]);
} else {
System.out.println("下标 " + index + " 越界了!数组长度只有 " + arr.length);
}
}

常见踩坑场景

循环条件写成 i <= arr.length,应该是 i < arr.length

以为最大下标等于长度,实际最大下标是 length - 1

数组长度为0时直接访问 arr[0]

多维数组

二维数组就是”数组的数组”,可以想象成一张 Excel 表格:行和列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Test
public void testMultiArray() {
System.out.println("=== 二维数组 ===");

// 静态初始化:3行4列的成绩表
int[][] scores = {
{90, 85, 78, 92}, // 第0行:同学A的4科成绩
{88, 76, 95, 80}, // 第1行:同学B
{70, 82, 89, 91} // 第2行:同学C
};

// 访问:scores[行][列]
System.out.println("同学B的第3科成绩:" + scores[1][2]); // 95

// 遍历二维数组
for (int i = 0; i < scores.length; i++) {
System.out.print("同学" + i + "的成绩:");
for (int j = 0; j < scores[i].length; j++) {
System.out.print(scores[i][j] + " ");
}
System.out.println();
}

// 动态初始化
int[][] matrix = new int[3][4]; // 3行4列,默认值全是0
matrix[0][0] = 1;
matrix[1][1] = 1;
matrix[2][2] = 1;
// 这就造了个类似单位矩阵的东西
}

理解方式int[][] arr 就是”int数组”的数组。arr[i] 拿到的是第 i 行(本身也是一个数组),arr[i][j] 才拿到具体那个元素

Arrays 工具类

Java 自带的数组工具箱,帮你干排序、打印、复制这些脏活累活

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Test
public void testArraysUtil() {
System.out.println("=== Arrays 工具类 ===");

// 需要导入:import java.util.Arrays;

int[] arr = {5, 2, 8, 1, 9, 3};

// 1. toString:把数组变成好看的字符串
// 直接打印数组会得到一堆乱码般的地址,用这个就对了
System.out.println(Arrays.toString(arr)); // [5, 2, 8, 1, 9, 3]

// 2. sort:排序(默认从小到大)
Arrays.sort(arr);
System.out.println("排序后:" + Arrays.toString(arr)); // [1, 2, 3, 5, 8, 9]

// 3. copyOf:复制数组(可以指定新长度)
int[] copy = Arrays.copyOf(arr, 3); // 只复制前3个
System.out.println("复制前3个:" + Arrays.toString(copy)); // [1, 2, 3]

int[] expanded = Arrays.copyOf(arr, 10); // 扩容,多出来的补0
System.out.println("扩容到10:" + Arrays.toString(expanded));

// 4. fill:用指定值填满数组
int[] filled = new int[5];
Arrays.fill(filled, 666);
System.out.println("fill后:" + Arrays.toString(filled)); // [666, 666, 666, 666, 666]

// 5. equals:比较两个数组内容是否相同
int[] a = {1, 2, 3};
int[] b = {1, 2, 3};
System.out.println("a == b:" + (a == b)); // false(比地址)
System.out.println("Arrays.equals:" + Arrays.equals(a, b)); // true(比内容)
}
方法 作用 示例
Arrays.toString(arr) 打印数组内容 [1, 2, 3]
Arrays.sort(arr) 排序(升序) [1, 2, 3, 5, 8, 9]
Arrays.copyOf(arr, len) 复制/扩容 复制前N个或扩容
Arrays.fill(arr, val) 填充 全部填成指定值
Arrays.equals(a, b) 比较内容 不比地址比内容

数组 vs ArrayList 预告

数组长度固定是它最大的限制。实际开发中,更常用的是 ArrayList,它是可以自动扩容的”高级数组”

对比项 数组 ArrayList
长度 固定,创建时确定 动态增长,自动扩容
类型 基本类型和引用类型都行 只能放引用类型(int要用Integer)
语法 arr[i] list.get(i)
增删元素 不支持(长度固定) add()remove() 随便搞
性能 稍快(直接内存访问) 稍慢(有封装开销)

结论:知道长度用数组,不知道用ArrayList。后面学集合框架的时候会详细讲

常见坑总结

说明 正确做法
下标从0开始 arr[1] 是第二个元素,不是第一个 时刻记住:第N个元素的下标是N-1
越界异常 访问不存在的下标直接崩 循环用 i < arr.length,别用 <=
直接打印数组 System.out.println(arr) 输出的是地址 Arrays.toString(arr)
数组比较 == 比较的是地址不是内容 Arrays.equals(a, b)
长度是属性不是方法 arr.length 没有括号 字符串才是 str.length() 有括号

练习题

题1:反转数组

{1, 2, 3, 4, 5} 变成 {5, 4, 3, 2, 1},不能用新数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
public void testReverse() {
int[] arr = {1, 2, 3, 4, 5};

// 思路:头尾互换,双指针往中间靠拢
int left = 0, right = arr.length - 1;
while (left < right) {
// 交换 arr[left] 和 arr[right]
int temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
left++;
right--;
}

System.out.println(Arrays.toString(arr)); // [5, 4, 3, 2, 1]
}

题2:找最大值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
public void testFindMax() {
int[] arr = {34, 78, 12, 95, 56, 23};

// 思路:擂台法,假设第一个是擂主,后面的依次来挑战
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i]; // 打赢了就换擂主
}
}

System.out.println("最大值:" + max); // 95
}

题3:冒泡排序

排序的经典入门算法,像水里的泡泡一样,大的数一轮一轮往后”冒”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Test
public void testBubbleSort() {
int[] arr = {5, 3, 8, 1, 2};

// 外层循环:要进行 n-1 轮
for (int i = 0; i < arr.length - 1; i++) {
// 内层循环:每轮比较相邻两个,大的往后挪
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}

System.out.println("排序后:" + Arrays.toString(arr)); // [1, 2, 3, 5, 8]
}

冒泡排序时间复杂度是 O(n^2),效率不高,实际开发直接用 Arrays.sort() 就行,但面试经常考手写


上一章 目录 下一章
流程控制 java基础 类与对象