
⭐️个体主页:Kidd
📚所属栏目:java

数组是Java中最基础的数据结构之一,用于存储同一数据类型的多个元素,具备固定长度、连续内存分配的特性,是后续学习集合框架、复杂算法的基础。二维数组可理解为"数组的数组",常用于存储表格化数据(如矩阵、报表)。本文将从数组与二维数组的核心概念出发,详细拆解创建、初始化、遍历的全流程,结合实操案例巩固用法,覆盖新手易踩的误区与注意事项。
一、Java数组核心认知
在Java中,数组属于引用数据类型,其元素可以是基本数据类型(int、char等)或引用数据类型(String、对象等)。核心特性如下:
-
固定长度:数组一旦创建,长度不可修改,若需动态调整元素数量,需借助集合(如ArrayList)。
-
同一类型:数组中所有元素必须是同一数据类型,不允许混合存储(如同时存储int和String)。
-
连续内存:数组元素在内存中连续分配,通过索引(下标)快速访问,索引从0开始,最大值为"长度-1"。
-
默认值:数组创建后,若未手动初始化,元素会被赋予对应类型的默认值(基本类型:int为0、boolean为false;引用类型为null)。
数组的本质是一个对象,JVM会为数组分配两块内存:栈内存存储数组引用(地址),堆内存存储数组的实际元素。
二、一维数组:创建、初始化与遍历
2.1 数组的三种创建方式
Java中创建一维数组有三种常用语法,可根据是否已知元素数量和具体值选择:
java
public class ArrayDemo {
public static void main(String[] args) {
// 方式1:指定长度,后续手动赋值(元素为默认值)
int[] arr1 = new int[5]; // 长度为5的int数组,元素默认值为0
// 方式2:直接初始化元素,长度由元素个数决定
int[] arr2 = new int[]{1, 2, 3, 4, 5}; // 长度为5,元素为指定值
// 方式3:简化语法(仅声明时可用,不可单独赋值)
int[] arr3 = {10, 20, 30}; // 等价于方式2,语法更简洁
}
}
注意事项:方式3的简化语法仅能用于声明并初始化的场景,不可拆分(如先声明int[] arr3; 再赋值arr3 = {10,20,30}; 会编译报错)。
2.2 数组的初始化与赋值
数组初始化分为静态初始化(创建时指定元素)和动态初始化(创建后手动赋值),两种方式可灵活搭配:
java
public class ArrayInitDemo {
public static void main(String[] args) {
// 动态初始化(先创建,后赋值)
String[] names = new String[3];
names[0] = "张三"; // 索引0赋值
names[1] = "李四"; // 索引1赋值
names[2] = "王五"; // 索引2赋值(最大索引,超出会抛ArrayIndexOutOfBoundsException)
// 静态初始化(创建时直接赋值)
double[] scores = {98.5, 89.0, 92.5, 78.0};
// 错误示范:数组长度不可修改,赋值时不可超出索引范围
// names[3] = "赵六"; // 索引越界异常
}
}
2.3 数组的三种遍历方式
遍历是数组的核心操作,用于依次访问数组中的每个元素,常用三种方式:普通for循环、增强for循环(foreach)、Arrays工具类。
java
import java.util.Arrays;
public class ArrayTraversalDemo {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
// 方式1:普通for循环(可通过索引修改元素,适合需操作索引的场景)
System.out.println("普通for循环遍历:");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
arr[i] *= 2; // 修改元素值(乘2)
}
System.out.println();
// 方式2:增强for循环(JDK5+,简化遍历,无法修改元素值,仅用于读取)
System.out.println("增强for循环遍历(修改后):");
for (int num : arr) {
System.out.print(num + " ");
}
System.out.println();
// 方式3:Arrays.toString()(工具类方法,直接打印数组内容,适合快速调试)
System.out.println("Arrays工具类遍历:" + Arrays.toString(arr));
}
}
运行结果:
Plain
普通for循环遍历:
1 2 3 4 5
增强for循环遍历(修改后):
2 4 6 8 10
Arrays工具类遍历:[2, 4, 6, 8, 10]
注意:增强for循环中变量是元素的副本,修改副本不会改变原数组元素;若需修改元素,必须使用普通for循环通过索引操作。
三、二维数组:创建、初始化与遍历
二维数组本质是"数组的数组",即外层数组的每个元素都是一个一维数组。Java中的二维数组支持"不规则数组"(内层数组长度可不同),这是与其他语言的区别之一。
3.1 二维数组的四种创建方式
java
public class TwoDimensionalArrayDemo {
public static void main(String[] args) {
// 方式1:指定外层数组长度和内层数组长度(规则数组)
int[][] arr1 = new int[3][4]; // 3行4列,共12个元素,默认值为0
// 方式2:指定外层长度,内层长度不指定(后续手动初始化,支持不规则数组)
int[][] arr2 = new int[3][];
arr2[0] = new int[2]; // 第1行长度为2
arr2[1] = new int[3]; // 第2行长度为3
arr2[2] = new int[4]; // 第3行长度为4(不规则数组)
// 方式3:静态初始化(规则数组,直接赋值)
int[][] arr3 = new int[][]{{1,2,3}, {4,5,6}, {7,8,9}}; // 3行3列
// 方式4:简化语法(规则/不规则均可)
int[][] arr4 = {{10,20}, {30,40,50}, {60}}; // 不规则数组
}
}
3.2 二维数组的初始化与赋值
二维数组赋值可通过"外层索引+内层索引"精准定位元素,规则数组和不规则数组赋值逻辑一致:
java
public class TwoDimensionalInitDemo {
public static void main(String[] args) {
// 动态初始化二维数组
String[][] students = new String[2][3]; // 2行3列(存储2个班级,每个班级3名学生)
students[0][0] = "一班-张三";
students[0][1] = "一班-李四";
students[0][2] = "一班-王五";
students[1][0] = "二班-赵六";
students[1][1] = "二班-孙七";
students[1][2] = "二班-周八";
// 静态初始化不规则数组
int[][] nums = {{1,2}, {3}, {4,5,6}};
nums[1][0] = 30; // 修改第2行第1个元素
nums[2][2] = 60; // 修改第3行第3个元素
}
}
3.3 二维数组的三种遍历方式
二维数组遍历需嵌套循环,外层循环遍历外层数组(行),内层循环遍历内层数组(列),常用三种方式:
java
import java.util.Arrays;
public class TwoDimensionalTraversalDemo {
public static void main(String[] args) {
int[][] arr = {{1,2,3}, {4,5,6}, {7,8,9}};
// 方式1:嵌套普通for循环(可修改元素,支持不规则数组)
System.out.println("嵌套普通for循环遍历:");
for (int i = 0; i < arr.length; i++) { // 外层遍历行
for (int j = 0; j < arr[i].length; j++) { // 内层遍历列(arr[i]为当前行的一维数组)
System.out.print(arr[i][j] + " ");
}
System.out.println(); // 换行
}
// 方式2:外层普通for+内层增强for(简化内层遍历,无法修改元素)
System.out.println("外层普通for+内层增强for遍历:");
for (int i = 0; i < arr.length; i++) {
for (int num : arr[i]) {
System.out.print(num + " ");
}
System.out.println();
}
// 方式3:Arrays.deepToString()(工具类方法,支持多维数组,快速打印)
System.out.println("Arrays工具类遍历多维数组:" + Arrays.deepToString(arr));
}
}
运行结果:
Plain
嵌套普通for循环遍历:
1 2 3
4 5 6
7 8 9
外层普通for+内层增强for遍历:
1 2 3
4 5 6
7 8 9
Arrays工具类遍历多维数组:[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
注意:遍历不规则数组时,内层循环需使用arr[i].length获取当前行的实际长度,避免索引越界。
四、数组实操案例:综合应用
案例1:一维数组求最值与求和
需求:计算一个int数组的最大值、最小值和总和,演示数组的遍历与元素操作。
java
public class ArrayCalcDemo {
public static void main(String[] args) {
int[] scores = {89, 98, 76, 85, 92, 78};
int max = scores[0]; // 假设第一个元素为最大值
int min = scores[0]; // 假设第一个元素为最小值
int sum = 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("最大值:" + max);
System.out.println("最小值:" + min);
System.out.printf("平均值:%.2f", avg); // 保留两位小数
}
}
运行结果:
Plain
数组总和:518
最大值:98
最小值:76
平均值:86.33
案例2:二维数组模拟矩阵转置
需求:将一个3x3矩阵(二维数组)转置(行变列、列变行),演示二维数组的遍历与赋值。
java
public class MatrixTransposeDemo {
public static void main(String[] args) {
// 原3x3矩阵
int[][] matrix = {{1,2,3}, {4,5,6}, {7,8,9}};
// 转置后的矩阵(行列数与原矩阵一致)
int[][] transpose = new int[3][3];
// 矩阵转置:transpose[j][i] = matrix[i][j]
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
transpose[j][i] = matrix[i][j];
}
}
// 打印原矩阵
System.out.println("原矩阵:");
for (int[] row : matrix) {
System.out.println(Arrays.toString(row));
}
// 打印转置后矩阵
System.out.println("转置后矩阵:");
for (int[] row : transpose) {
System.out.println(Arrays.toString(row));
}
}
}
运行结果:
Plain
原矩阵:
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
转置后矩阵:
[1, 4, 7]
[2, 5, 8]
[3, 6, 9]
五、数组常见误区与注意事项
-
索引越界异常(ArrayIndexOutOfBoundsException):最常见错误,访问数组时索引超出"0~长度-1"范围,需通过数组.length控制循环边界。
-
空指针异常(NullPointerException):数组未初始化(仅声明未创建)或内层数组未初始化时访问元素,如int[][] arr = new int[3][]; arr[0][0] = 1;(arr[0]为null)。
-
数组长度不可修改:数组创建后长度固定,若需添加/删除元素,需创建新数组并复制原元素(或使用ArrayList)。
-
基本类型与引用类型数组区别:基本类型数组存储元素值,引用类型数组存储对象地址,修改引用类型数组元素会改变原对象内容。
-
Arrays工具类使用:Arrays.toString()用于一维数组,Arrays.deepToString()用于多维数组,不可混用(多维数组用toString()会打印地址)。
数组作为Java基础数据结构,是后续学习集合、IO流、算法的重要铺垫,掌握其创建、初始化、遍历的核心逻辑,能大幅提升代码编写效率。实际开发中,若需动态调整元素数量,优先使用ArrayList等集合框架,但数组在性能敏感场景(如高频遍历、固定长度数据存储)中仍有不可替代的优势。