×

开篇引子——为什么需要数组?

想象一下:你要存班上 50 个人的成绩。没有数组的话——

int score1 = 85;
int score2 = 92;
int score3 = 67;
// ... 写 50 行?
int score50 = 78;

而想求个平均分?手写 score1 + score2 + ... + score50?写到第四十个你就怀疑人生了。这就是数组存在的理由——把同类型数据组织起来,用下标统一访问。

一、一维数组的定义

1.1 声明和初始化

Java 里数组是一个引用类型,有固定的长度,一旦创建就不能改变。这是它和集合类的最大区别。

// 方式一:声明 + 分配空间
int[] scores = new int[5];
// scores[0]~scores[4] 默认都是 0

// 方式二:声明 + 直接赋值
int[] scores2 = {85, 92, 67, 78, 90};

// 方式三:先声明,再 new
int[] scores3;
scores3 = new int[]{85, 92, 67, 78, 90};  // 注意这里不能省略 new int[]

// 不推荐的写法(c语言风格,Java也支持但别这么写)
int scores4[] = new int[5];

三种声明方式的区别:

方式使用场景
new int[5]先占位,后面再逐个赋值
{85, 92, ...}创建时就确定所有值
new int[]{85, 92, ...}变量声明和赋值分两行,或者需要传参

数组的长度的获取用 数组名.length,注意不是方法,是属性。

int[] arr = {10, 20, 30, 40, 50};
System.out.println(arr.length);  // 5

1.2 默认值

new 了空间但不赋值的话,元素有默认值:

类型默认值
byte/short/int/long0
float/double0.0
char‘u0000’(空字符)
booleanfalse
引用类型(String、对象等)null

这个默认值机制挺方便的,比如你统计某个范围内数字出现的次数,整型数组一创建全是 0,可以直接自增。

二、数组的遍历

遍历就是”把数组每个元素过一遍”。Java 提供了两种方式:

2.1 for 循环(下标遍历)

int[] scores = {85, 92, 67, 78, 90};
for (int i = 0; i < scores.length; i++) {
    System.out.println("第" + (i + 1) + "个成绩:" + scores[i]);
}

这是最经典的遍历方式。优点:能拿到下标,方便修改元素。缺点:写法啰嗦了点。

2.2 增强 for 循环(foreach)

for (int score : scores) {
    System.out.println(score);
}

Java 5 引入的语法糖。优点:代码简洁、不会有下标越界问题。缺点:拿不到下标,也不能修改数组元素(修改的是临时变量)。

2.3 用 Arrays.toString() 快速打印

调试时最常用的方式:

import java.util.Arrays;

int[] scores = {85, 92, 67, 78, 90};
System.out.println(Arrays.toString(scores));
// 输出:[85, 92, 67, 78, 90]

千万别直接打印数组变量:

System.out.println(scores);
// 输出:[I@1b6d3586  ← 哈希地址,不是内容!

💡 我在大学上 Java 课时,第一次打印数组直接传了变量名,输出一串看不懂的东西,以为程序出 bug 了……后来同学告诉我要用 Arrays.toString()。如果你也踩过这个坑,你不是一个人。

三、数组的常见操作

3.1 求最大值和最小值

int[] arr = {5, 3, 9, 1, 7, 6};

// 求最大值
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
    if (arr[i] > max) {
        max = arr[i];
    }
}
System.out.println("最大值:" + max);  // 9

// 求最小值同理,把 > 换成 <
int min = arr[0];
for (int i = 1; i < arr.length; i++) {
    if (arr[i] < min) {
        min = arr[i];
    }
}
System.out.println("最小值:" + min);  // 1

注意:初始值设为 arr[0],不要设成 0Integer.MAX_VALUE——万一数组里全是负数,max = 0 就错了。

3.2 求和与平均值

int[] scores = {85, 92, 67, 78, 90};
int sum = 0;

for (int score : scores) {
    sum += score;
}

double avg = (double) sum / scores.length;
System.out.println("总分:" + sum);      // 412
System.out.println("平均分:" + avg);    // 82.4

这里要把 sum 强转成 double,否则两个 int 相除结果会被截断为整数。
比如 412 / 5 = 82(而不是 82.4),这坑当年我也踩过。

3.3 查找元素

int[] arr = {5, 3, 9, 1, 7, 6};
int target = 7;
int index = -1;  // -1 表示未找到

for (int i = 0; i < arr.length; i++) {
    if (arr[i] == target) {
        index = i;
        break;  // 找到了就退出,别继续白找
    }
}

if (index != -1) {
    System.out.println(target + " 在位置 " + index);
} else {
    System.out.println(target + " 不在数组中");
}

这是线性查找,最朴素的查找方式。对于无序数组这是唯一的选择;对于有序数组,后面会学到二分查找,效率更高。

3.4 数组元素反转

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

for (int i = 0, j = arr.length - 1; i < j; i++, j--) {
    // 交换 arr[i] 和 arr[j]
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

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

关键点:只遍历一半,用两个指针从两端向中间走。i < j 保证了奇数长度时中间元素不动。

3.5 数组拷贝

int[] src = {1, 2, 3, 4, 5};

// 方式一:for 循环手动拷贝
int[] dest1 = new int[src.length];
for (int i = 0; i < src.length; i++) {
    dest1[i] = src[i];
}

// 方式二:System.arraycopy()(原生方法,效率最高)
int[] dest2 = new int[src.length];
System.arraycopy(src, 0, dest2, 0, src.length);

// 方式三:Arrays.copyOf()(最方便)
int[] dest3 = Arrays.copyOf(src, src.length);

// 方式四:clone()
int[] dest4 = src.clone();

几个 copyOf 的妙用:

// 截取前3个元素
int[] part1 = Arrays.copyOf(src, 3);       // [1, 2, 3]

// 扩展长度(多余位置补0)
int[] expanded = Arrays.copyOf(src, 7);   // [1, 2, 3, 4, 5, 0, 0]

// 复制指定范围(from 包含,to 不包含)
int[] range = Arrays.copyOfRange(src, 1, 4);  // [2, 3, 4]

3.6 冒泡排序(入门级排序)

排序算法是面试常客,但作为初学者,先掌握冒泡排序就够了——它最直观,也最容易理解排序的”比较-交换”思想。

int[] arr = {5, 3, 9, 1, 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 temp = arr[j];
            arr[j] = arr[j + 1];
            arr[j + 1] = temp;
        }
    }
}

System.out.println(Arrays.toString(arr));  // [1, 3, 5, 7, 9]

原理图解:每一轮把当前未排序部分的最大值”冒泡”到最后。arr.length - 1 - i 表示每轮比较次数递减——最后面的元素已经排好了,不需要再比。

四、常见陷阱和注意事项

4.1 数组下标越界

数组下标从 0 开始,到 length - 1 结束。访问 arr[arr.length] 会抛出 ArrayIndexOutOfBoundsException——这是初学者最常见的异常之一。

int[] arr = {1, 2, 3};
System.out.println(arr[3]);  // ❌ 运行报错!下标最大是 2

4.2 空指针访问

int[] arr = null;
System.out.println(arr.length);  // ❌ NullPointerException
// 数组是引用类型,不 new 就是 null,调 length 会崩

4.3 foreach 里不能修改原数组

int[] arr = {1, 2, 3};
for (int x : arr) {
    x = 100;  // ❌ 这只是改了一个临时变量,原数组没变
}
System.out.println(Arrays.toString(arr));  // 还是 [1, 2, 3]

想修改数组元素,必须用下标 for 循环。

五、综合示例:学生成绩管理系统(简易版)

把今天学的操作串起来,写一个小程序:

import java.util.Arrays;

public class ScoreManager {
    public static void main(String[] args) {
        // 5 个学生的成绩
        int[] scores = {76, 88, 62, 95, 81};
        
        // 1. 打印原始成绩
        System.out.println("原始成绩:" + Arrays.toString(scores));
        
        // 2. 统计
        int sum = 0;
        int max = scores[0];
        int min = scores[0];
        for (int score : scores) {
            sum += score;
            if (score > max) max = score;
            if (score < min) min = score;
        }
        double avg = (double) sum / scores.length;
        
        System.out.println("总分:" + sum);
        System.out.println("平均分:" + avg);
        System.out.println("最高分:" + max);
        System.out.println("最低分:" + min);
        
        // 3. 查找 95 分的位置
        int target = 95;
        int index = -1;
        for (int i = 0; i < scores.length; i++) {
            if (scores[i] == target) {
                index = i;
                break;
            }
        }
        System.out.println(target + " 分在第 " + (index + 1) + " 位");
        
        // 4. 按成绩从低到高排序
        int[] sorted = Arrays.copyOf(scores, scores.length);
        Arrays.sort(sorted);  // 直接用工具类排序
        System.out.println("按成绩排序:" + Arrays.toString(sorted));
        
        // 5. 找出不及格(低于 60 分)的人数
        // 这里没有不及格的,但方法学会了
        int failCount = 0;
        for (int score : scores) {
            if (score < 60) failCount++;
        }
        System.out.println("不及格人数:" + failCount);
    }
}

运行结果:

原始成绩:[76, 88, 62, 95, 81]
总分:402
平均分:80.4
最高分:95
最低分:62
95 分在第 4 位
按成绩排序:[62, 76, 81, 88, 95]
不及格人数:0

总结

  • 数组是长度固定的同类型数据容器,下标从 0 开始,访问越界会抛异常
  • 声明方式int[] arr = new int[n]{值1, 值2}new int[]{值1, 值2} 三种
  • 遍历用 for 下标循环(能修改元素)或 foreach(只读)
  • 常用操作:求和、求最值、查找、反转、拷贝、排序
  • 工具类 Arrays.toString()Arrays.sort() 让日常操作简洁很多

下一篇我们聊多维数组Arrays 工具类的更多用法,还会讲到可变参数——到时候你会发现很多操作根本不需要手写循环了。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

作者

2248768396@qq.com

相关文章

09. 数组与方法综合练习

开篇引子 前面三篇文章讲了数组(一维、二维、...

读出全部

08. 方法详解:定义、重载、递归与值传递

开篇引子——为什么要有方法? 我们的代码一直...

读出全部