A06 数组:定义、遍历、查找、排序与常见边界坑(配练习)

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 方法:参数传递(值传递)、重载、可变参数与常见坑(带例子)》

你会发现:把数组操作封装成方法,代码会干净很多,这也是写项目必须掌握的能力。

相关推荐
2501_944525545 小时前
Flutter for OpenHarmony 个人理财管理App实战 - 预算详情页面
android·开发语言·前端·javascript·flutter·ecmascript
heartbeat..5 小时前
Redis 中的锁:核心实现、类型与最佳实践
java·数据库·redis·缓存·并发
Prince-Peng5 小时前
技术架构系列 - 详解Redis
数据结构·数据库·redis·分布式·缓存·中间件·架构
5 小时前
java关于内部类
java·开发语言
好好沉淀5 小时前
Java 项目中的 .idea 与 target 文件夹
java·开发语言·intellij-idea
gusijin5 小时前
解决idea启动报错java: OutOfMemoryError: insufficient memory
java·ide·intellij-idea
To Be Clean Coder5 小时前
【Spring源码】createBean如何寻找构造器(二)——单参数构造器的场景
java·后端·spring
lsx2024065 小时前
FastAPI 交互式 API 文档
开发语言
吨~吨~吨~5 小时前
解决 IntelliJ IDEA 运行时“命令行过长”问题:使用 JAR
java·ide·intellij-idea
你才是臭弟弟5 小时前
SpringBoot 集成MinIo(根据上传文件.后缀自动归类)
java·spring boot·后端