1. 开篇:生活中的“数组”——从储物柜说起

大家好!如果你是刚开始学习Java的大一新生,听到“数组”这个词可能会觉得有点抽象。别担心,今天我们就用生活中最常见的例子来理解它。

想象一下学校的储物柜:一排排整齐的柜子,每个柜子都有一个编号(001、002、003…),你可以把书包、运动鞋、课本分别放进不同的柜子里。数组就是编程世界里的“储物柜系统”——它是一组相同类型的数据的集合,每个数据都有一个编号(我们叫它“下标”),你可以通过编号快速找到对应的数据。

再比如:

  • 排队点名:老师按照学号顺序点名,学号就是“下标”,同学就是“数据”
  • Excel表格:表格的行和列组成一个二维结构,每个单元格都有固定位置
  • 药店的药盒:每个小格子放着不同的药,但整个药盒是一个整体

数组的作用很简单:让大量同类型数据变得有序、好管理。如果没有数组,你要管理100个学生的成绩,就得创建100个变量,那得多麻烦啊!

2. 一维数组:你的第一个“数据储物柜”

2.1 如何创建数组?

在Java中,创建数组有两种方式,就像买储物柜一样:

方式一:先买柜子,后放东西(声明后赋值)

// 第一步:声明一个能放5个整数的"柜子"
int[] scores = new int[5];

// 第二步:往柜子里放东西
scores[0] = 85;  // 第一个柜子放85分
scores[1] = 92;  // 第二个柜子放92分
scores[2] = 78;
scores[3] = 95;
scores[4] = 88;  // 第五个柜子放88分

内存示意图:

堆内存 (Heap)

栈内存 (Stack)

指向

scores (引用)
0x1234

数组对象
int[5]

[0] → 85

[1] → 92

[2] → 78

[3] → 95

[4] → 88

说明:scores 是栈内存中的引用变量,存储着数组对象在堆内存中的地址(如0x1234)。new int[5] 在堆内存中创建了一个包含5个整数的数组对象。

方式二:连柜子带东西一起买(声明时直接赋值)

// 直接创建一个放了5个分数的数组
int[] scores = {85, 92, 78, 95, 88};
// 或者这样写也可以
int[] scores = new int[]{85, 92, 78, 95, 88};

内存示意图:

堆内存 (Heap)

栈内存 (Stack)

指向

scores (引用)
0x5678

数组对象
int[5]

[0] → 85

[1] → 92

[2] → 78

[3] → 95

[4] → 88

说明:这种方式同样会在堆内存中创建数组对象,并立即初始化所有元素。栈内存中的 scores 引用变量指向这个已经填充好数据的数组对象。两种方式最终的内存结构是一样的,只是创建和初始化的时机不同。

2.2 访问数组元素:记住“下标从0开始”

这是新手最容易迷糊的地方!在Java中,数组的下标(编号)是从0开始的,不是从1开始。

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

System.out.println(fruits[0]);  // 输出:苹果(第一个元素)
System.out.println(fruits[1]);  // 输出:香蕉(第二个元素)
System.out.println(fruits[3]);  // 输出:葡萄(第四个元素)

// 数组长度:用 .length 获取
System.out.println("水果数组有 " + fruits.length + " 种水果");  // 输出:4

2.3 遍历数组:看看柜子里都有什么

遍历就是“挨个查看”数组里的所有元素。最常用的是for循环:

int[] scores = {85, 92, 78, 95, 88};

// 方法一:普通for循环(知道下标时用)
for (int i = 0; i < scores.length; i++) {
    System.out.println("第" + (i+1) + "个成绩是:" + scores[i]);
}

// 方法二:增强for循环(只关心值,不关心下标时用)
for (int score : scores) {
    System.out.println("成绩:" + score);
}

2.4 实战案例:找出最高分

让我们用刚学的知识解决一个实际问题:找出全班成绩中的最高分。

public class FindMaxScore {
    public static void main(String[] args) {
        // 1. 创建成绩数组
        int[] scores = {85, 92, 78, 95, 88, 91, 76};
        
        // 2. 假设第一个成绩是最高分
        int maxScore = scores[0];
        
        // 3. 遍历数组,逐个比较
        for (int i = 1; i < scores.length; i++) {
            if (scores[i] > maxScore) {
                maxScore = scores[i];  // 发现更高的分数就更新
            }
        }
        
        // 4. 输出结果
        System.out.println("全班最高分是:" + maxScore);
    }
}

运行结果:

全班最高分是:95

3. 二维数组:升级版“表格储物柜”

3.1 什么是二维数组?

如果说一维数组是一排储物柜,那么二维数组就是一个储物柜墙——有行有列,像Excel表格一样。

// 创建一个3行4列的二维数组(3个学生,每个学生4门课成绩)
int[][] scoreTable = new int[3][4];

// 也可以直接赋值
int[][] scoreTable = {
    {85, 92, 78, 95},  // 第一个学生的4门课成绩
    {88, 76, 90, 82},  // 第二个学生
    {92, 85, 79, 96}   // 第三个学生
};

3.2 理解行和列:用“楼层-房间号”类比

想象一栋宿舍楼:

  • 第一维(行):楼层(1楼、2楼、3楼)
  • 第二维(列):房间号(101、102、103)
// 访问第2层第3个房间(注意下标从0开始!)
int[][] dorm = new int[5][10];  // 5层楼,每层10个房间
dorm[1][2] = 25;  // 2楼3号房间住着25号同学

// 遍历二维数组(两层循环)
for (int floor = 0; floor < dorm.length; floor++) {
    for (int room = 0; room < dorm[floor].length; room++) {
        System.out.print(dorm[floor][room] + " ");
    }
    System.out.println();  // 换行,每层楼一行
}

3.3 实用案例:矩阵相乘

矩阵相乘是二维数组的经典应用。假设我们要计算两个矩阵A和B的乘积:

A = [1, 2]   B = [5, 6]
    [3, 4]       [7, 8]

计算规则:C[i][j] = A的第i行 × B的第j列(对应元素相乘再相加)

public class MatrixMultiplication {
    public static void main(String[] args) {
        // 定义两个2×2矩阵
        int[][] A = {{1, 2}, {3, 4}};
        int[][] B = {{5, 6}, {7, 8}};
        int[][] C = new int[2][2];  // 结果矩阵
        
        // 矩阵相乘
        for (int i = 0; i < 2; i++) {          // 遍历A的行
            for (int j = 0; j < 2; j++) {      // 遍历B的列
                C[i][j] = 0;
                for (int k = 0; k < 2; k++) {  // 对应元素相乘相加
                    C[i][j] += A[i][k] * B[k][j];
                }
            }
        }
        
        // 输出结果
        System.out.println("矩阵相乘结果:");
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 2; j++) {
                System.out.print(C[i][j] + " ");
            }
            System.out.println();
        }
    }
}

运行结果:

矩阵相乘结果:
19 22 
43 50

4. Arrays工具类:数组的“瑞士军刀”

Java提供了一个超级好用的工具类——Arrays,它就像数组的“瑞士军刀”,里面有很多现成的方法可以直接用。

4.1 常用方法一览

import java.util.Arrays;  // 记得先导入

public class ArraysDemo {
    public static void main(String[] args) {
        int[] numbers = {5, 2, 8, 1, 9};
        
        // 1. 排序(从小到大)
        Arrays.sort(numbers);
        System.out.println("排序后:" + Arrays.toString(numbers));
        // 输出:[1, 2, 5, 8, 9]
        
        // 2. 二分查找(必须先排序!)
        int index = Arrays.binarySearch(numbers, 8);
        System.out.println("数字8的位置是:" + index);  // 输出:3
        
        // 3. 数组转字符串(方便打印)
        String str = Arrays.toString(numbers);
        System.out.println("数组字符串:" + str);
        
        // 4. 填充数组(所有元素赋相同值)
        int[] filled = new int[5];
        Arrays.fill(filled, 100);
        System.out.println("填充后:" + Arrays.toString(filled));
        // 输出:[100, 100, 100, 100, 100]
        
        // 5. 比较两个数组是否相等
        int[] arr1 = {1, 2, 3};
        int[] arr2 = {1, 2, 3};
        System.out.println("数组相等吗?" + Arrays.equals(arr1, arr2));
        // 输出:true
    }
}

4.2 实训案例:中文名称排序

Arrays.sort()默认按字母顺序排序,对于中文,它会按Unicode编码排序(基本上是拼音顺序):

import java.util.Arrays;

public class ChineseSort {
    public static void main(String[] args) {
        String[] names = {"王小明", "李华", "张三", "赵四", "刘五"};
        
        System.out.println("排序前:");
        for (String name : names) {
            System.out.print(name + " ");
        }
        // 输出:王小明 李华 张三 赵四 刘五
        
        Arrays.sort(names);
        
        System.out.println("\n排序后:");
        for (String name : names) {
            System.out.print(name + " ");
        }
        // 输出:李华 刘五 王小明 张三 赵四(按拼音首字母排序)
    }
}

5. 新手避坑指南:这些错误千万别犯!

❌ 错误1:下标从1开始

int[] arr = {10, 20, 30};
System.out.println(arr[1]);  // 输出20,不是10!
// 记住:arr[0]才是第一个元素

❌ 错误2:数组长度固定后还想加元素

int[] arr = new int[3];
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
// arr[3] = 4;  // 报错!数组只有3个位置,下标3不存在

如果需要“可变长度”的集合,以后可以学习ArrayList

❌ 错误3:数组下标越界

int[] arr = {1, 2, 3};
System.out.println(arr[3]);  // 报错:ArrayIndexOutOfBoundsException
// 有效下标是0、1、2,3已经“越界”了

❌ 错误4:混合存放不同类型数据

// 错误写法:数组里不能既有整数又有字符串
Object[] mixed = {1, "hello", 3.14};  // 虽然编译能过,但非常不推荐

// 正确做法:同类型数据放一起
int[] numbers = {1, 2, 3};
String[] words = {"hello", "world"};

❌ 错误5:直接打印数组

int[] arr = {1, 2, 3};
System.out.println(arr);  // 输出:[I@1b6d3586(内存地址,不是内容)

// 正确做法:
System.out.println(Arrays.toString(arr));  // 输出:[1, 2, 3]

6. 总结与思考

📚 知识点回顾

  1. 一维数组:像一排储物柜,通过下标访问元素,下标从0开始
  2. 二维数组:像表格或矩阵,有行和列两个维度
  3. Arrays工具类:提供了排序、查找、填充等实用方法
  4. 遍历数组:用for循环或增强for循环
  5. 常见错误:下标越界、长度固定、类型必须一致

💡 简单思考题

  1. 创建一个长度为10的整数数组,放入1~10,然后计算所有偶数的和

    参考代码提示:

    // 创建数组并赋值
    int[] arr = new int[10];
    for (int i = 0; i < arr.length; i++) {
        arr[i] = i + 1; // 放入1~10
    }
    
    // 计算偶数之和
    int sum = 0;
    for (int num : arr) {
        if (num % 2 == 0) { // 判断是否为偶数
            sum += num;
        }
    }
    System.out.println("偶数之和:" + sum);
    
  2. 有一个5×5的二维数组,如何求出对角线(从左上到右下)上所有元素的和?

    参考代码提示:

    // 假设有一个5×5的二维数组matrix
    int[][] matrix = new int[5][5];
    // ... 这里假设数组已经填充了数据
    
    // 计算主对角线元素之和
    int diagonalSum = 0;
    for (int i = 0; i < matrix.length; i++) {
        // 主对角线元素的行列索引相同
        diagonalSum += matrix[i][i];
    }
    System.out.println("对角线之和:" + diagonalSum);
    
  3. 如果让你用数组存储一个班级50个学生的姓名和成绩,你会设计什么样的数据结构?

  4. Arrays.sort()方法对字符串数组排序时,是按照什么规则排序的?

🎯 学习建议

数组是Java中最基础、最重要的数据结构之一。刚开始可能会觉得下标从0开始不习惯,多写几个程序就适应了。记住:

  • 先理解概念(储物柜、表格的类比)
  • 再动手写代码(从简单遍历开始)
  • 最后尝试解决实际问题(找最大值、矩阵计算等)

当你熟练使用数组后,学习后面的集合(ArrayList、HashMap等)就会轻松很多。数组是基石,一定要打牢基础!


小提示:本文所有代码都可以直接复制到Java开发环境中运行。建议你亲手敲一遍代码,运行看看结果,这样理解会更深刻。遇到问题不要怕,编程就是在不断“试错-修改”中进步的。加油!🚀

更多推荐