Java 数组总结

作者:没有四次元口袋的蓝胖
日期:2026-06-02
标签:Java, 基础语法, 数组


一、什么是数组?

数组是相同类型数据的有序集合,在内存中连续存储。核心特点:

特性 说明
固定长度 创建后长度不可变
同类型 所有元素类型一致
连续内存 通过索引高效随机访问
索引从 0 开始 最后一个元素索引为 length - 1

二、一维数组

2.1 声明与初始化

声明(两种写法等价)
int[] arr;      // 推荐,类型和变量分离清晰
int arr[];      // C 风格,不推荐
静态初始化(声明时直接赋值)
int[] arr = {1, 2, 3, 4, 5};

// 完整写法
int[] arr = new int[]{1, 2, 3, 4, 5};
动态初始化(指定长度,默认值填充)
int[] arr = new int[5];  // 5个元素,默认值为 0

各类型默认值:

数据类型 默认值
byte / short / int / long 0
float / double 0.0
char '\u0000'
boolean false
引用类型(String 等) null

2.2 访问与遍历

通过索引访问
int[] arr = {10, 20, 30};
System.out.println(arr[0]);   // 10
System.out.println(arr[2]);   // 30
arr[1] = 99;                  // 修改
System.out.println(arr[1]);   // 99

⚠️ 索引越界会抛出 ArrayIndexOutOfBoundsException,这是运行时异常,编译器不会提前报错。

三种遍历方式
int[] arr = {10, 20, 30, 40, 50};

// 1. 普通 for(可获取索引,可修改元素)
for (int i = 0; i < arr.length; i++) {
    System.out.println("arr[" + i + "] = " + arr[i]);
}

// 2. 增强 for / for-each(简洁,但拿不到索引)
for (int num : arr) {
    System.out.println(num);
}

// 3. Arrays.toString()(快速打印,调试常用)
System.out.println(Arrays.toString(arr));
// 输出:[10, 20, 30, 40, 50]

2.3 常见操作

求最大值 / 最小值
int[] arr = {34, 12, 89, 5, 67};

int max = arr[0], 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);  // 89
System.out.println("最小值:" + min);  // 5
求和与平均值
int[] arr = {10, 20, 30, 40};
int sum = 0;
for (int num : arr) {
    sum += num;
}
double avg = (double) sum / arr.length;
System.out.println("总和:" + sum);       // 100
System.out.println("平均值:" + avg);     // 25.0
查找元素
int[] arr = {5, 3, 8, 1, 9};
int target = 8;
int index = -1;

for (int i = 0; i < arr.length; i++) {
    if (arr[i] == target) {
        index = i;
        break;
    }
}
System.out.println("索引:" + index);  // 2
反转数组
int[] arr = {1, 2, 3, 4, 5};

for (int i = 0, j = arr.length - 1; i < j; i++, j--) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}
System.out.println(Arrays.toString(arr));
// 输出:[5, 4, 3, 2, 1]

三、二维数组

3.1 概念

二维数组本质是**“数组的数组”**——每个元素本身又是一个一维数组。

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

内存视角:

arr ──→ [ 引用1 ,  引用2 ,  引用3 ]
           │        │        │
           ▼        ▼        ▼
        [1,2,3]  [4,5,6]  [7,8,9]

3.2 声明与初始化

静态初始化
int[][] arr = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};
动态初始化——规则矩阵
// 3行4列,所有元素默认为 0
int[][] arr = new int[3][4];
动态初始化——不规则矩阵(锯齿数组)
// 只指定行数,列数后续单独分配
int[][] arr = new int[3][];
arr[0] = new int[2];   // 第0行:2列
arr[1] = new int[4];   // 第1行:4列
arr[2] = new int[1];   // 第2行:1列

这是 Java 二维数组的灵活性所在:每行的列数可以不同,因为它本质上是一维引用数组。


3.3 访问与遍历

访问元素
int[][] arr = {
    {1, 2, 3},
    {4, 5, 6}
};
System.out.println(arr[0][1]);   // 2(第0行第1列)
System.out.println(arr[1][2]);   // 6(第1行第2列)
System.out.println(arr.length);      // 2(行数)
System.out.println(arr[0].length);   // 3(第0行的列数)
遍历方式
int[][] arr = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

// 1. 嵌套 for 循环
for (int i = 0; i < arr.length; i++) {
    for (int j = 0; j < arr[i].length; j++) {
        System.out.print(arr[i][j] + " ");
    }
    System.out.println();
}

// 2. 嵌套 for-each
for (int[] row : arr) {
    for (int num : row) {
        System.out.print(num + " ");
    }
    System.out.println();
}

// 3. Arrays.deepToString()(调试神器)
System.out.println(Arrays.deepToString(arr));
// 输出:[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

3.4 常见操作

矩阵转置
int[][] matrix = {
    {1, 2, 3},
    {4, 5, 6}
};
// 2×3 → 3×2

int rows = matrix.length;
int cols = matrix[0].length;
int[][] transposed = new int[cols][rows];

for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
        transposed[j][i] = matrix[i][j];
    }
}
// transposed = {{1,4}, {2,5}, {3,6}}
对角线求和
int[][] arr = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

int mainSum = 0;    // 主对角线
int antiSum = 0;    // 副对角线
for (int i = 0; i < arr.length; i++) {
    mainSum += arr[i][i];
    antiSum += arr[i][arr.length - 1 - i];
}
System.out.println("主对角线和:" + mainSum);   // 15 (1+5+9)
System.out.println("副对角线和:" + antiSum);   // 15 (3+5+7)
杨辉三角
int n = 6;
int[][] triangle = new int[n][];

for (int i = 0; i < n; i++) {
    triangle[i] = new int[i + 1];
    triangle[i][0] = 1;                        // 每行首元素
    triangle[i][i] = 1;                        // 每行末元素
    for (int j = 1; j < i; j++) {
        triangle[i][j] = triangle[i-1][j-1] + triangle[i-1][j];
    }
}

for (int[] row : triangle) {
    System.out.println(Arrays.toString(row));
}
// [1]
// [1, 1]
// [1, 2, 1]
// [1, 3, 3, 1]
// [1, 4, 6, 4, 1]
// [1, 5, 10, 10, 5, 1]

四、Arrays 工具类常用方法

java.util.Arrays 是操作数组的工具类,面试和开发都高频使用。

方法 作用 示例
toString() 一维数组转字符串 Arrays.toString(arr)
deepToString() 多维数组转字符串 Arrays.deepToString(arr2D)
sort() 升序排序(双轴快排) Arrays.sort(arr)
binarySearch() 二分查找(需先排序) Arrays.binarySearch(arr, 5)
fill() 填充相同值 Arrays.fill(arr, 0)
equals() 比较一维数组内容 Arrays.equals(a, b)
deepEquals() 比较多维数组内容 Arrays.deepEquals(a, b)
copyOf() 复制指定长度 Arrays.copyOf(arr, 10)
copyOfRange() 复制指定范围 Arrays.copyOfRange(arr, 1, 4)
使用示例
int[] arr = {5, 2, 8, 1, 9, 3};

// 排序
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
// [1, 2, 3, 5, 8, 9]

// 二分查找(必须先排序)
int idx = Arrays.binarySearch(arr, 5);
System.out.println("5 的索引:" + idx);  // 3

// 复制并扩容
int[] newArr = Arrays.copyOf(arr, 10);
System.out.println(Arrays.toString(newArr));
// [1, 2, 3, 5, 8, 9, 0, 0, 0, 0]

// 填充
Arrays.fill(newArr, 6, 10, 100);
System.out.println(Arrays.toString(newArr));
// [1, 2, 3, 5, 8, 9, 100, 100, 100, 100]

五、数组常见坑与面试考点

坑 1:数组引用赋值 vs 拷贝

int[] a = {1, 2, 3};
int[] b = a;        // 引用赋值!a 和 b 指向同一个数组
b[0] = 99;
System.out.println(a[0]);  // 99 ← a 也被修改了

// 正确的拷贝方式
int[] c = Arrays.copyOf(a, a.length);  // 深拷贝
c[0] = 0;
System.out.println(a[0]);  // 99 ← a 不受影响

坑 2:数组长度不可变

int[] arr = {1, 2, 3};
// arr.length = 5;  // 编译错误!length 是 final 的

// 想"扩容"只能创建新数组
arr = Arrays.copyOf(arr, 5);  // [1, 2, 3, 0, 0]

坑 3:二维数组每行长度可以不同

int[][] arr = new int[3][];
arr[0] = new int[2];
arr[1] = new int[4];
arr[2] = new int[1];

// 遍历时不能用 arr[0].length 代表所有行的列数!
// 必须用 arr[i].length 逐行获取

坑 4:Arrays.sort() 是升序,如何降序?

// 方法1:装箱后用 Comparator(只能对引用类型)
Integer[] arr = {5, 2, 8, 1, 9};
Arrays.sort(arr, Collections.reverseOrder());

// 方法2:升序排完后手动反转
int[] arr2 = {5, 2, 8, 1, 9};
Arrays.sort(arr2);
// 反转...

面试高频题:数组 vs ArrayList

对比维度 数组 ArrayList
长度 固定 动态扩容
存储类型 基本类型 + 引用类型 只能引用类型(int → Integer)
速度 更快(无装箱开销) 略慢
功能 基础 丰富(add/remove/contains 等)
使用场景 长度已知、性能敏感 长度可变、操作频繁

六、思维导图速览

数组
├── 一维数组
│   ├── 声明与初始化(静态 / 动态)
│   ├── 访问与遍历(for / for-each / toString)
│   ├── 常见操作(最值 / 求和 / 查找 / 反转)
│   └── 默认值(0 / null / false)
├── 二维数组
│   ├── 本质:数组的数组
│   ├── 初始化(规则 / 锯齿)
│   ├── 遍历(嵌套循环 / deepToString)
│   └── 常见操作(转置 / 对角线 / 杨辉三角)
├── Arrays 工具类
│   ├── sort / binarySearch / fill
│   ├── copyOf / copyOfRange
│   ├── toString / deepToString
│   └── equals / deepEquals
└── 常见坑
    ├── 引用赋值 ≠ 拷贝
    ├── 长度不可变
    ├── 锯齿数组行宽不同
    └── 降序排序技巧

写在最后

数组是 Java 最基础的数据结构,也是后续学习集合框架、排序算法、动态规划的重要基石。建议:

  1. 动手敲:杨辉三角、矩阵转置这些题目,自己从零写一遍比看十遍有用。
  2. 理解引用模型:Java 数组是引用类型,搞清楚"赋值是共享还是拷贝"能避免很多 bug。
  3. 关注边界:空数组(arr.length == 0)和 null 数组是两个概念,别混淆。

更多推荐