【Java SE 基础学习打卡】37 二维数组

目录

  • 前言
  • 一、二维数组概述:数组的数组,存表格型数据的利器
    • [1.1 生活化类比](#1.1 生活化类比)
    • [1.2 编程定义](#1.2 编程定义)
    • [1.3 直观结构(以 3 行 2 列的成绩表为例)](#1.3 直观结构(以 3 行 2 列的成绩表为例))
  • 二、二维数组的定义与初始化:造好表格式收纳盒
    • [2.1 定义格式(2 种,推荐第 1 种)](#2.1 定义格式(2 种,推荐第 1 种))
    • [2.2 静态初始化:直接往表格里填全部数据](#2.2 静态初始化:直接往表格里填全部数据)
    • [2.3 动态初始化:先定表格大小,再填数据](#2.3 动态初始化:先定表格大小,再填数据)
    • [2.4 关键提醒:静态 / 动态初始化不可混用](#2.4 关键提醒:静态 / 动态初始化不可混用)
  • 三、二维数组的访问与遍历:操作表格的每个单元格
    • [3.1 单个元素访问:定位表格的 "行 + 列"](#3.1 单个元素访问:定位表格的 “行 + 列”)
    • [3.2 二维数组的遍历:遍历表格的所有单元格](#3.2 二维数组的遍历:遍历表格的所有单元格)
    • [3.3 两种遍历方式对比(新手选对不踩坑)](#3.3 两种遍历方式对比(新手选对不踩坑))
  • 四、二维数组的长度:外层行长度,内层列长度(可不一致)
  • 五、二维数组的简单应用:存储并打印班级各科成绩表
  • [六、新手必避的 5 个 "二维数组致命坑"](#六、新手必避的 5 个 “二维数组致命坑”)
    • [6.1 坑 1:行列索引搞反(最常见)](#6.1 坑 1:行列索引搞反(最常见))
    • [6.2 坑 2:遍历不规则数组,内层用固定列数](#6.2 坑 2:遍历不规则数组,内层用固定列数)
    • [6.3 坑 3:动态初始化不规则数组,直接访问内层元素](#6.3 坑 3:动态初始化不规则数组,直接访问内层元素)
    • [6.4 坑 4:混淆二维数组的外层 / 内层长度](#6.4 坑 4:混淆二维数组的外层 / 内层长度)
    • [6.5 坑 5 增强 for 循环试图修改二维数组元素](#6.5 坑 5 增强 for 循环试图修改二维数组元素)
  • 总结

前言

上一节咱们吃透了一维数组的各种操作,它像一个 "单排格子的收纳盒",适合存单列数据 ------ 比如一个班级的数学成绩。但实际编程中,更多是表格型数据:比如班级学生的语文、数学、英语三科成绩(行是学生,列是科目)、超市商品的名称和价格(行是商品,列是属性),这时候一维数组就不够用了。

二维数组就是为了解决这个问题而来,它像一个 "多排多列的表格式收纳盒",本质是 "数组的数组"。这一节咱们从二维数组的核心概念入手,讲清定义初始化、访问遍历、长度获取的规则,重点说明 "内层数组长度可不一致" 的特点,最后结合班级成绩表的实战场景,让新手能落地使用二维数组处理表格数据!

一、二维数组概述:数组的数组,存表格型数据的利器

1.1 生活化类比

对比一维数组和二维数组,用收纳盒 + 表格直观理解:

  • 一维数组:单排 5 格的收纳盒,存 5 个学生的数学成绩(单列数据);

  • 二维数组:3 行 3 列的表格收纳盒,存 3 个学生的语数外三科成绩(3 行 = 3 个学生,3 列 = 3 科,表格型数据)。

1.2 编程定义

二维数组的本质是数组的数组:外层是一个一维数组,它的每个元素又都是一个一维数组(内层数组)。

  • 外层数组:对应表格的

  • 内层数组:对应表格的

  • 核心作用:专门存储行、列结构的表格型数据,比如成绩表、价目表、矩阵等。

1.3 直观结构(以 3 行 2 列的成绩表为例)

java 复制代码
int[][] scores = {{90,85}, {88,92}, {95,89}};
// 外层数组(行):[ [90,85], [88,92], [95,89] ]
// 内层数组(列):第0行[90,85]、第1行[88,92]、第2行[95,89]

二、二维数组的定义与初始化:造好表格式收纳盒

和一维数组一致,二维数组先定义再初始化,定义有 2 种格式(推荐规范写法),初始化分静态 (知道所有数据)和动态 (先定行列,后续赋值),且支持不规则二维数组(内层数组长度不同)。

2.1 定义格式(2 种,推荐第 1 种)

推荐格式(规范、直观,一眼识别二维数组)

java 复制代码
数据类型[][] 数组名;

示例:

java 复制代码
int[][] scores; // 存整型成绩表
double[][] prices; // 存浮点型价格表
String[][] names; // 存字符串型二维数据

兼容格式(不推荐,仅了解,兼容 C/C++ 语法)

java 复制代码
数据类型 数组名[][];

示例:

java 复制代码
int scores[][]; // 效果同上,可读性差

2.2 静态初始化:直接往表格里填全部数据

适合已知所有表格数据的场景,不用指定行列数,系统会根据元素自动计算外层(行)和内层(列)长度,支持规则 / 不规则二维数组。

语法格式(2 种,同一维数组)

java 复制代码
// 完整格式
数据类型[][] 数组名 = new 数据类型[][]{{元素1,元素2}, {元素3,元素4}, ...};
// 简化格式(常用,声明时直接赋值)
数据类型[][] 数组名 = {{元素1,元素2}, {元素3,元素4}, ...};

代码示例 1:规则二维数组(内层长度一致,3 行 2 列)

java 复制代码
// 3个学生,2科成绩(规则:每行都是2列)
int[][] scores = {{90,85}, {88,92}, {95,89}};

代码示例 2:不规则二维数组(内层长度不一致,重点)

二维数组的核心特性之一:内层数组长度可以不同,像 "参差不齐的表格",系统完全支持。

java 复制代码
// 第0行2列,第1行3列,第2行1列(不规则)
int[][] nums = {{1,2}, {3,4,5}, {6}};

2.3 动态初始化:先定表格大小,再填数据

适合只知道表格行列数,数据后续确定的场景,分 2 种情况,新手优先掌握规则二维数组的初始化。

方式 1:规则二维数组(指定总行数 + 总列数,推荐)

一次性指定外层(行)和内层(列)长度,所有内层数组长度一致,系统会给每个元素赋默认值(和一维数组默认值规则完全一致)。

语法格式

java 复制代码
数据类型[][] 数组名 = new 数据类型[总行数][总列数];

代码示例(3 行 3 列,默认值都是 0,后续赋值)

java 复制代码
public class Array2DDynamic1 {
    public static void main(String[] args) {
        // 动态初始化:3行3列的int二维数组,所有元素默认0
        int[][] scores = new int[3][3];
        // 手动给表格赋值:行0列0=90(第1个学生第1科)
        scores[0][0] = 90;
        scores[0][1] = 85;
        scores[0][2] = 92;
        scores[1][0] = 88;
        // 未赋值的元素保持默认值0
        System.out.println(scores[1][1]); // 输出0
    }
}

方式 2:不规则二维数组(先定行数,再逐个初始化列数)

先指定外层数组长度(总行数),内层数组暂时为 null,后续手动为每一行指定不同的列数,实现不规则二维数组。

语法格式

java 复制代码
// 1. 先定总行数,内层数组未初始化
数据类型[][] 数组名 = new 数据类型[总行数][];
// 2. 逐个初始化内层数组(列数可不同)
数组名[0] = new 数据类型[列数1];
数组名[1] = new 数据类型[列数2];

代码示例(3 行,列数分别为 2、3、1)

java 复制代码
public class Array2DDynamic2 {
    public static void main(String[] args) {
        // 1. 先定3行,内层数组暂为null
        int[][] nums = new int[3][];
        // 2. 逐个初始化列数,实现不规则
        nums[0] = new int[2]; // 第0行2列
        nums[1] = new int[3]; // 第1行3列
        nums[2] = new int[1]; // 第2行1列
        // 赋值并访问
        nums[0][1] = 5;
        nums[1][2] = 8;
        System.out.println(nums[0][1]); // 输出5
        System.out.println(nums[1][2]); // 输出8
    }
}

2.4 关键提醒:静态 / 动态初始化不可混用

和一维数组一样,不能既指定行列数,又直接填元素,编译直接报错:

java 复制代码
// 错误示例:规则动态初始化+静态赋值,混用报错
int[][] scores = new int[3][2]{{90,85}, {88,92}};

三、二维数组的访问与遍历:操作表格的每个单元格

3.1 单个元素访问:定位表格的 "行 + 列"

二维数组的每个元素对应表格的一个单元格 ,通过 "行索引 + 列索引" 精准访问,行、列索引都从0开始,支持赋值和取值。

核心语法

java 复制代码
// 取值:数组名[行索引][列索引]
数组名[行索引][列索引];
// 赋值:数组名[行索引][列索引] = 对应类型值;
数组名[行索引][列索引] = 值;

代码示例(3 行 2 列成绩表,存取操作)

java 复制代码
public class Array2DAccess {
    public static void main(String[] args) {
        int[][] scores = {{90,85}, {88,92}, {95,89}};
        // 取值:第0行第1列(第1个学生第2科)
        int score1 = scores[0][1];
        System.out.println("第1个学生第2科成绩:" + score1); // 输出85
        
        // 赋值:修改第2行第0列(第3个学生第1科)为98
        scores[2][0] = 98;
        System.out.println("修改后第3个学生第1科成绩:" + scores[2][0]); // 输出98
    }
}

3.2 二维数组的遍历:遍历表格的所有单元格

二维数组是 "数组的数组",遍历需要双重循环 :外层循环控制 ,内层循环控制,常用 2 种方式,根据场景选择。

方式 1:双重普通 for 循环(万能遍历,可改元素、获索引)

适用场景

  • 需要行 / 列索引的场景(比如求某行 / 某列的和);

  • 想要修改二维数组的元素值;

  • 支持不规则二维数组(内层用arr[i].length控制列数)。

代码示例(遍历 3 行 2 列规则数组,修改元素 + 打印)

java 复制代码
public class Array2DFor {
    public static void main(String[] args) {
        int[][] scores = {{90,85}, {88,92}, {95,89}};
        System.out.println("遍历并修改成绩(每题加2分):");
        // 外层循环:控制行,i是行索引
        for (int i = 0; i < scores.length; i++) {
            // 内层循环:控制列,j是列索引,scores[i].length是第i行的列数
            for (int j = 0; j < scores[i].length; j++) {
                scores[i][j] += 2; // 所有成绩加2分
                System.out.print(scores[i][j] + " "); // 打印每行的元素
            }
            System.out.println(); // 每行打印完换行,保持表格格式
        }
    }
}

执行结果(保持表格样式)

java 复制代码
遍历并修改成绩(每题加2分):
92 87 
90 94 
97 91 

方式 2:双重增强 for 循环(foreach,只读遍历,代码简洁)

适用场景

  • 仅需要读取所有元素值,不需要修改;

  • 不需要行 / 列索引,仅打印表格数据;

  • 代码更简洁,无需关注索引,降低越界风险。

核心逻辑

  • 外层增强 for 循环:遍历外层数组,每次获取一行(一个内层一维数组);

  • 内层增强 for 循环:遍历当前行的内层数组,每次获取一个单元格的值。

代码示例(仅读取并打印不规则二维数组)

java 复制代码
public class Array2DForeach {
    public static void main(String[] args) {
        // 不规则二维数组:第0行2列,第1行3列,第2行1列
        int[][] nums = {{1,2}, {3,4,5}, {6}};
        System.out.println("双重增强for循环遍历不规则数组:");
        // 外层:遍历每一行(row是每个内层一维数组)
        for (int[] row : nums) {
            // 内层:遍历当前行的每个元素
            for (int num : row) {
                System.out.print(num + " ");
            }
            System.out.println(); // 换行保持表格格式
        }
    }
}

执行结果

java 复制代码
双重增强for循环遍历不规则数组:
1 2 
3 4 5 
6 

3.3 两种遍历方式对比(新手选对不踩坑)

遍历方式 能否获行 / 列索引 能否修改元素 能否适配不规则数组 代码简洁度
双重普通 for 循环 能(用 arr [i].length) 稍繁琐
双重增强 for 循环 不能 不能 能(自动适配) 很简洁

四、二维数组的长度:外层行长度,内层列长度(可不一致)

新手最容易混淆二维数组的长度,记住核心规则:二维数组有两个长度,外层是行数,内层是对应行的列数,且内层列数可不同(不规则数组)。

核心语法

java 复制代码
数组名.length; // 外层长度:二维数组的总行数
数组名[行索引].length; // 内层长度:第行索引行的总列数

代码示例(规则 + 不规则数组,打印长度)

java 复制代码
public class Array2DLength {
    public static void main(String[] args) {
        // 1. 规则二维数组:3行2列
        int[][] scores = {{90,85}, {88,92}, {95,89}};
        System.out.println("规则数组-总行数:" + scores.length); // 外层长度3
        System.out.println("规则数组-第0行列数:" + scores[0].length); // 内层长度2
        System.out.println("规则数组-第2行列数:" + scores[2].length); // 内层长度2

        // 2. 不规则二维数组:3行,列数2/3/1
        int[][] nums = {{1,2}, {3,4,5}, {6}};
        System.out.println("\n不规则数组-总行数:" + nums.length); // 外层长度3
        System.out.println("不规则数组-第0行列数:" + nums[0].length); // 内层长度2
        System.out.println("不规则数组-第1行列数:" + nums[1].length); // 内层长度3
        System.out.println("不规则数组-第2行列数:" + nums[2].length); // 内层长度1
    }
}

执行结果

java 复制代码
规则数组-总行数:3
规则数组-第0行列数:2
规则数组-第2行列数:2

不规则数组-总行数:3
不规则数组-第0行列数:2
不规则数组-第1行列数:3
不规则数组-第2行列数:1

关键避坑:遍历不规则数组,内层循环必须用arr[i].length

如果内层循环用固定值或外层长度,会触发索引越界异常

java 复制代码
// 错误示例:遍历不规则数组,内层用固定值3,第0行只有2列,访问nums[0][2]报错
for (int i = 0; i < nums.length; i++) {
    for (int j = 0; j < 3; j++) {
        System.out.print(nums[i][j] + " ");
    }
}

五、二维数组的简单应用:存储并打印班级各科成绩表

结合以上所有知识点,做一个实战场景:存储 3 个学生的语、数、外三科成绩,打印标准成绩表,并计算每个学生的总分,新手可直接运行代码,落地掌握。

完整代码

java 复制代码
public class Array2DApp {
    public static void main(String[] args) {
        // 1. 静态初始化:3个学生(行),语数外3科(列)
        int[][] scores = {{90, 85, 92}, {88, 92, 89}, {95, 89, 96}};
        // 打印表头
        System.out.println("========== 班级成绩表 ==========");
        System.out.println("学生\t语文\t数学\t英语\t总分");
        System.out.println("===============================");

        // 2. 双重普通for循环遍历,计算每个学生总分并打印
        for (int i = 0; i < scores.length; i++) {
            int sum = 0; // 每个学生的总分,每行初始化一次
            System.out.print("第" + (i+1) + "个\t"); // 打印学生序号
            for (int j = 0; j < scores[i].length; j++) {
                sum += scores[i][j]; // 累加各科成绩求总分
                System.out.print(scores[i][j] + "\t"); // 打印各科成绩
            }
            System.out.println(sum); // 打印当前学生总分,换行
        }
        System.out.println("===============================");
    }
}

执行结果(标准表格格式)

java 复制代码
========== 班级成绩表 ==========
学生	语文	数学	英语	总分
===============================
第1个	90	85	92	267
第2个	88	92	89	269
第3个	95	89	96	280
===============================

六、新手必避的 5 个 "二维数组致命坑"

6.1 坑 1:行列索引搞反(最常见)

  • 错误示例:想访问第 0 行第 1 列,写成列索引在前

    java 复制代码
    scores[1][0]; // 原本想取第1个学生第2科,实际取第2个学生第1科
  • 避坑:记死顺序数组名 [行索引][列索引],行在前,列在后。

6.2 坑 2:遍历不规则数组,内层用固定列数

  • 错误示例:内层循环用固定值,导致索引越界

    java 复制代码
    for (int j = 0; j < 3; j++) {} // 不规则数组某行不足3列,直接报错
  • 避坑:内层循环固定写j < 数组名[i].length,自动适配每行的列数。

6.3 坑 3:动态初始化不规则数组,直接访问内层元素

  • 错误示例:只定行数,未初始化内层数组,直接赋值

    java 复制代码
    int[][] nums = new int[3][];
    nums[0][0] = 1; // 内层数组为null,运行时报空指针异常
  • 避坑:先初始化内层数组,再访问 / 赋值:nums[0] = new int[2]; nums[0][0] = 1;

6.4 坑 4:混淆二维数组的外层 / 内层长度

  • 错误示例:想取列数,直接用数组名.length

    java 复制代码
    int col = scores.length; // 实际取的是行数3,不是列数2
  • 避坑:列数没有统一值,取指定行 的列数:scores[0].length

6.5 坑 5 增强 for 循环试图修改二维数组元素

  • 错误示例:以为修改内层变量能改变原数组

    java 复制代码
    for (int[] row : scores) {
        for (int num : row) {
            num += 2; // 仅修改临时变量,原数组无变化
        }
    }
  • 避坑:要修改二维数组元素,必须用双重普通 for 循环

总结

这一节咱们掌握了二维数组的核心知识和实操技能,记住 4 个核心点:

  1. 本质与作用:数组的数组,用于存储行列表格型数据,外层是行,内层是列;

  2. 初始化:静态(已知所有数据)、动态(先定行列),支持不规则数组(内层长度不同);

  3. 访问与遍历:行 + 列索引定位元素,双重普通 for 循环可改元素,双重增强 for 循环仅只读;

  4. 长度规则:数组名.length是总行数,数组名[i].length是第 i 行的列数,内层可不一致。

二维数组是处理结构化数据的基础,掌握后能应对大部分批量表格数据的存储和操作场景。

相关推荐
皮皮哎哟2 天前
冒泡排序与数组传递全解析 一维二维指针数组及二级指针应用指南
c语言·算法·冒泡排序·二维数组·指针数组·传参·二级指针
编程火箭车10 天前
【Java SE 基础学习打卡】36 数组的常见操作
冒泡排序·java se·java 基础·线性查找·数组常见操作·数组增删改·数组拷贝
编程火箭车11 天前
【Java SE 基础学习打卡】35 数组元素的访问与遍历
数组索引·java se·java 基础·java 数组·数组元素访问与遍历·普通 for 循环·增强 for 循环
编程火箭车14 天前
【Java SE 基础学习打卡】34 数组的定义与初始化
java se·java 基础·java 数组·数组定义与初始化·静态初始化·动态初始化·length 属性
编程火箭车15 天前
【Java SE 基础学习打卡】33 数组的概述
java se·java 基础·数组概述·数组核心特征·java 数组·批量存储数据·连续内存存储
编程火箭车16 天前
【Java SE 基础学习打卡】32 方法的嵌套调用与递归调用
java se·java 基础·java 方法·方法嵌套调用·方法递归调用·递归终止条件·递归应用场景
编程火箭车17 天前
【Java SE 基础学习打卡】31 方法的返回值与void关键字
java se·java 基础·return 语句·编程小白入门·java 方法·方法返回值·void 关键字
汉克老师18 天前
GESP2025年9月认证C++二级真题与解析(编程题2(菱形))
c++·找规律·二维数组·枚举算法·曼哈顿距离·模拟画图
编程火箭车19 天前
【Java SE 基础学习打卡】28 方法的定义与调用
java se·参数传递·返回值·java 基础·新手避坑·java 方法·方法定义与调用