A06 数组:定义、遍历、查找、排序与常见边界坑
【本节目标】
学完这一篇,你应该能做到:
1)掌握数组的定义、初始化、访问与长度获取
2)会用 for / 增强 for 遍历数组,并知道两者区别
3)能实现常见需求:查找最大最小、查找某元素、统计次数、反转数组
4)理解数组的默认值、越界异常、引用类型数组的"空指针"风险
5)掌握两种排序思路:调用工具类排序 + 手写冒泡排序(理解原理)
一、数组到底是什么?(一句话讲清)
数组 = 一组"相同类型"的数据,按顺序存放在一起,用下标(index)访问。
你可以把数组理解成:
"一个固定长度的盒子排成一排,每个盒子只能放同一种类型的东西"。
数组的特点:
-
长度固定(创建后不能变长/变短)
-
下标从 0 开始
-
访问快(根据下标直接定位)
-
适合存"数量已知/不经常变化"的数据
二、数组的定义与初始化(最常用的 3 种写法)
2.1 先声明再创建
java
int[] arr;
arr = new int[5]; // 长度为 5,默认值全是 0
2.2 声明 + 创建(常用)
java
int[] arr = new int[5];
2.3 直接给初值(最常见)
java
int[] arr = {10, 20, 30, 40};
提示:
-
new int[5]只确定长度,值是默认值 -
{...}这种写法,长度由元素个数决定
三、数组的访问与 length(最重要的两行)
数组访问:arr[index]
数组长度:arr.length
java
int[] arr = {10, 20, 30};
System.out.println(arr[0]); // 10
System.out.println(arr.length); // 3
arr[1] = 99;
System.out.println(arr[1]); // 99
四、遍历数组:for vs 增强 for(新手必会)
4.1 普通 for(最常用,能拿到下标)
java
int[] arr = {10, 20, 30};
for (int i = 0; i < arr.length; i++) {
System.out.println("i=" + i + ", value=" + arr[i]);
}
4.2 增强 for(for-each,更简洁但没有下标)
java
int[] arr = {10, 20, 30};
for (int x : arr) {
System.out.println(x);
}
什么时候用哪一个?
-
需要下标、需要修改数组元素:用普通 for
-
只读遍历、打印、求和:增强 for 更爽
五、常见数组需求(你写业务/刷题会天天用)
5.1 求数组元素和 / 平均值
java
int[] arr = {10, 20, 30};
int sum = 0;
for (int x : arr) {
sum += x;
}
double avg = sum * 1.0 / arr.length;
System.out.println("sum=" + sum);
System.out.println("avg=" + avg);
5.2 找最大值 / 最小值(经典)
java
int[] arr = {5, 1, 9, 3, 7};
int max = arr[0];
int min = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) max = arr[i];
if (arr[i] < min) min = arr[i];
}
System.out.println("max=" + max);
System.out.println("min=" + min);
5.3 查找某个元素(线性查找)
java
int[] arr = {5, 1, 9, 3, 7};
int target = 3;
int index = -1; // -1 表示没找到
for (int i = 0; i < arr.length; i++) {
if (arr[i] == target) {
index = i;
break;
}
}
System.out.println("index=" + index);
5.4 统计出现次数
java
int[] arr = {1, 2, 1, 3, 1, 4};
int target = 1;
int count = 0;
for (int x : arr) {
if (x == target) {
count++;
}
}
System.out.println("count=" + count);
5.5 反转数组(双指针)
java
int[] arr = {10, 20, 30, 40, 50};
int left = 0;
int right = arr.length - 1;
while (left < right) {
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
六、数组排序:两种方式(工具类 + 手写冒泡)
6.1 方式 1:工具类排序(实际开发常用)
java
import java.util.Arrays;
int[] arr = {5, 1, 9, 3, 7};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
6.2 方式 2:冒泡排序(理解排序思想)
冒泡核心:每一轮把"最大值"冒到最后。
java
int[] arr = {5, 1, 9, 3, 7};
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 tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
说明:
-
外层控制轮数(length - 1 轮)
-
内层每轮比较并交换相邻元素
-
- i是优化:最后 i 个元素已经有序
七、数组的"默认值"与常见边界坑(高频必踩)
7.1 默认值是什么?
创建数组但不赋值时,会有默认值:
-
int/short/byte/long:0
-
double/float:0.0
-
char:'\u0000'(不可见字符)
-
boolean:false
-
引用类型(如 String):null
java
String[] names = new String[3];
System.out.println(names[0]); // null
7.2 常见坑 1:数组越界(IndexOutOfBounds)
最典型的错误:循环边界写错。
正确:i < arr.length
错误:i <= arr.length
7.3 常见坑 2:引用类型数组的空指针(NPE)
java
String[] names = new String[3];
System.out.println(names[0].length()); // 这里会 NPE,因为 names[0] 是 null
解决思路:
-
使用前先判空
-
或者初始化数组元素
7.4 常见坑 3:数组是引用类型,传参会"影响原数组"
java
public static void change(int[] arr) {
arr[0] = 999;
}
public static void main(String[] args) {
int[] arr = {1, 2, 3};
change(arr);
System.out.println(arr[0]); // 999
}
结论:
方法里改数组元素,会影响外面的数组(因为传的是引用的拷贝)。
八、一个小综合例子:学生成绩统计(更像真实业务)
【需求】
输入 5 个学生成绩,输出:平均分、最高分、最低分、是否有人不及格(<60)。
java
import java.util.Scanner;
public class ScoreDemo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int[] scores = new int[5];
for (int i = 0; i < scores.length; i++) {
System.out.println("请输入第 " + (i + 1) + " 个成绩:");
scores[i] = sc.nextInt();
}
int sum = 0;
int max = scores[0];
int min = scores[0];
boolean hasFail = false;
for (int s : scores) {
sum += s;
if (s > max) max = s;
if (s < min) min = s;
if (s < 60) hasFail = true;
}
double avg = sum * 1.0 / scores.length;
System.out.println("平均分:" + avg);
System.out.println("最高分:" + max);
System.out.println("最低分:" + min);
System.out.println("是否有人不及格:" + (hasFail ? "是" : "否"));
}
}
这段代码把"数组 + 循环 + if + 三目"都串起来了,很适合作为阶段练习。
九、本节小练习(从易到难)
练习 1:给一个 int 数组,输出所有元素,并计算总和
练习 2:写一个方法 findIndex(int[] arr, int target),返回 target 的下标(找不到返回 -1)
练习 3:写一个方法 reverse(int[] arr),把数组原地反转
练习 4:手写冒泡排序并打印每一轮排序后的数组(用于理解过程)
练习 5(进阶):输入 N 个整数,找出"出现次数最多的数字"(提示:先用数组做统计/或后面用 Map)
本节小结
1)数组是同类型数据的"固定长度容器",下标从 0 开始
2)遍历用 for(有下标)或增强 for(简洁)
3)常见操作:求和、找最大最小、查找、统计、反转、排序
4)最常见 Bug:越界、空指针、修改原数组
5)工具类排序实际开发常用,冒泡排序用于理解算法思想
下一篇预告(A07)
《A07 方法:参数传递(值传递)、重载、可变参数与常见坑(带例子)》
你会发现:把数组操作封装成方法,代码会干净很多,这也是写项目必须掌握的能力。