05、Java 基础硬核复习:数组的本质与面试考点

第一部分:核心知识体系

1. 数组概述

数组是存储同类型数据的连续内存块,通过索引(下标)快速访问元素。其核心特点包括:

  • 长度固定:创建后无法动态改变大小(需通过新建数组+复制实现扩容)。
  • 类型一致:所有元素必须为同一数据类型(基本类型或引用类型)。
  • 索引访问:通过 数组名[索引] 访问元素,索引从 0 开始。

2. 一维数组的基本使用

(1)初始化方式

  • 静态初始化:直接指定元素值,长度由元素个数决定。

    1
    int[] arr1 = new int[]{1, 2, 3}; // 或简化为 int[] arr1 = {1, 2, 3};
  • 动态初始化:指定长度,元素默认初始化(如 int 类型默认为 0)。

    1
    int[] arr2 = new int[3]; // arr2 = [0, 0, 0]

(2)核心操作

  • 长度:通过 数组名.length 获取(如 arr1.length 为 3)。

  • 元素访问:通过索引访问(如 arr1[0] 为 1)。

  • 遍历:使用 for 循环或 foreach(增强 for 循环)。

    1
    for (int num : arr1) { System.out.println(num); }

3. 二维数组的基本使用

二维数组本质是“数组的数组”,即每个元素是一维数组。

(1)初始化方式

  • 静态初始化:直接指定行和列的元素值。

    1
    int[][] arr3 = new int[][]{{1, 2}, {3}}; // 或简化为 {{1,2},{3}}
  • 动态初始化:指定行数和列数,元素默认初始化。

    1
    int[][] arr4 = new int[2][3]; // arr4 = [[0,0,0], [0,0,0]]

(2)核心操作

  • 长度arr3.length 为行数(2),arr3[0].length 为第一行的列数(2)。

  • 遍历:通过嵌套循环访问每个元素。

    1
    2
    3
    4
    5
    for (int i = 0; i < arr3.length; i++) {
    for (int j = 0; j < arr3[i].length; j++) {
    System.out.print(arr3[i][j] + " ");
    }
    }

4. 元素默认初始化值

  • 基本类型int/short/long 为 0,double/float 为 0.0,booleanfalsechar'\u0000'(空字符)。
  • 引用类型:所有引用类型(如 String、自定义类)默认为 null

5. 数组的常见算法

(1)特征值计算

  • 求和、平均值、最大值、最小值:通过遍历数组累加或比较得到。

    1
    2
    int sum = 0;
    for (int num : arr1) { sum += num; }

(2)赋值与复制

  • 直接赋值:引用传递(修改副本会影响原数组)。

    1
    2
    int[] arr5 = arr1; // arr5 和 arr1 指向同一内存地址
    arr5[0] = 10; // arr1[0] 也变为 10
  • 深拷贝:通过 Arrays.copyOf()clone() 创建新数组(修改副本不影响原数组)。

    1
    2
    int[] arr6 = Arrays.copyOf(arr1, arr1.length);
    arr6[0] = 20; // arr1[0] 仍为 10

(3)反转与扩容

  • 反转:从数组两端交换元素(如 arr1[0]arr1[2] 交换)。

  • 扩容:新建更大长度的数组,通过 System.arraycopy()Arrays.copyOf() 复制原数组元素。

    1
    int[] newArr = Arrays.copyOf(arr1, arr1.length + 1); // 扩容 1 位

(4)查找与排序

  • 顺序查找:遍历数组,适用于无序数组(时间复杂度 O(n))。
  • 二分查找:前提是数组有序,通过不断缩小范围查找(时间复杂度 O(log n))。
  • 排序算法
    • 冒泡排序:相邻元素比较,大的后移(稳定,时间复杂度 O(n²))。
    • 快速排序:分治法,选基准分区(平均时间复杂度 O(n log n))。

6. Arrays 工具类

Java 提供的数组操作工具类,常用方法包括:

  • Arrays.sort(arr):排序(基本类型默认升序)。
  • Arrays.binarySearch(arr, target):二分查找(需先排序)。
  • Arrays.toString(arr):打印数组内容(如 [1, 2, 3])。
  • Arrays.copyOf(arr, newLength):复制数组(可扩容/缩容)。

第二部分:高频面试考点

1. 数组初始化的区别

  • 静态 vs 动态:静态初始化直接赋值,长度由元素个数决定;动态初始化指定长度,元素默认初始化。
  • 面试陷阱:动态初始化后未赋值直接使用(如 int[] arr = new int[3]; System.out.println(arr[0]); 输出 0,而非报错)。

2. 内存解析:一维 vs 二维数组

  • 一维数组:连续内存块,元素紧密排列(如 int[] arr = {1,2,3} 在内存中连续存储 1、2、3)。
  • 二维数组:数组元素是一维数组,每个一维数组独立存储(如 int[][] arr = {{1,2}, {3,4}} 中,arr[0]arr[1] 是两个独立的内存块)。
  • 面试陷阱:二维数组行长度可不同(如 int[][] arr = new int[2][]; arr[0] = new int[3]; arr[1] = new int[2];),需注意遍历时的列长度判断。

3. 常见算法的手写实现

  • 冒泡排序:需掌握相邻元素比较的逻辑,注意边界条件(如 j < arr.length - 1 - i)。
  • 快速排序:需理解分治思想(选基准、分区、递归),面试常考其时间复杂度和稳定性(不稳定)。
  • 二分查找:需注意数组必须有序,否则结果不可靠;返回值为 -(插入点+1)(未找到时)。

4. Arrays 工具类的异常

  • 空指针异常(NullPointerException):对 null 数组调用 Arrays.sort()toString() 时抛出。
  • 角标越界异常(ArrayIndexOutOfBoundsException):访问索引超出 length-1(如 arr[3] 对长度为 3 的数组)。
  • 面试陷阱binarySearch 前未排序会导致结果错误(如对 [3,1,2] 调用 binarySearch(1) 可能返回错误索引)。

5. 数组复制的深浅拷贝

  • 浅拷贝(直接赋值):引用传递,修改副本会影响原数组。
  • 深拷贝(Arrays.copyOf/clone):创建新数组,修改副本不影响原数组。
  • 面试陷阱:混淆两者,导致数据意外修改(如将原数组传递给方法后,方法内修改了副本,原数组也被修改)。

总结

数组是 Java 编程的基石,掌握其初始化、内存布局及常见算法是面试的核心要求。通过理解底层逻辑(如连续内存、引用传递),能快速定位问题并写出高效代码。基础不牢,地动山摇,扎实掌握数组知识将为后续学习集合框架、算法打下坚实基础。