Java:数组的定义和使用(万字解析)

Java 中的数组(Array) 是最基础、最常用的固定长度、连续存储的数据结构。它属于引用数据类型,在堆内存中分配空间。

下面从零基础到高级、从语法到内存到最佳实践全面解析(目标约万字深度,但这里精炼为结构清晰的完整指南,适合学习、面试、日常开发使用)。内容基于 Java 21+(2025–2026 主流写法)

1. 为什么 Java 需要数组?(核心定位)

  • 存储大量同类型数据
  • 提供O(1) 随机访问(下标访问)
  • 内存连续 → 缓存友好,性能极高
  • 长度不可变 → 这是数组最大局限(对比 ArrayList)

2. 数组的四种基本声明方式(语法糖演变)

写法序号声明语法推荐程度(2026年)说明
1int[] arr;★★★★★最推荐,可读性强(类型在前)
2int arr[];★★☆☆☆C/C++ 风格,不推荐
3int... arr (可变参数)仅用于方法参数,本质是数组
4int @Nullable[] arr (注解风格)★★★★☆现代项目中常见(配合空安全工具)

推荐统一风格:始终使用 类型[] 变量名(方式1)。

3. 数组的创建(初始化)方式全解(最常考)

3.1 方式一:静态初始化(最常用、最安全)

// 方式一:完整写法(new + 花括号)
int[] scores = new int[]{85, 92, 78, 95};

// 方式二:简化写法(推荐,编译器自动推断 new int[])
int[] scores = {85, 92, 78, 95};          // 只能在声明时使用

String[] names = {"Alice", "Bob", "Charlie"};

// 空数组(长度0)
int[] empty = new int[0];                 // 或 {}
int[] empty2 = {};                        // 同上

3.2 方式二:动态初始化(先创建,后赋值)

// 先声明 + 创建(默认值填充)
int[] arr = new int[5];          // 长度5,全部初始化为 0

// 基本类型默认值一览(非常重要!)
byte/short/int/long → 0
float/double        → 0.0
char                → ''
boolean             → false
引用类型(String等) → null
// 逐个赋值
arr[0] = 10;
arr[1] = 20;
// ...

3.3 方式三:先声明,后 new(延迟初始化)

int[] arr;               // 只声明,栈中存 null
arr = new int[10];       // 堆中真正分配

4. 多维数组(本质:数组的数组)

Java 没有真正的多维数组,只有数组的数组(jagged array,不规则数组)。

4.1 规则矩形二维数组(最常见)

// 声明 + 创建(3行4列)
int[][] matrix = new int[3][4];

// 静态初始化
int[][] matrix2 = {
    {1, 2, 3, 4},
    {5, 6, 7, 8},
    {9,10,11,12}
};

// 访问:matrix[行][列]
matrix[0][0] = 100;
System.out.println(matrix[2][3]);  // 12

4.2 不规则(锯齿状)二维数组(面试高频)

int[][] jagged = new int[3][];     // 第一维必须指定

jagged[0] = new int[2];            // 长度2
jagged[1] = new int[5];            // 长度5
jagged[2] = new int[1];            // 长度1

// 更常见写法
int[][] jagged2 = {
    {1, 2},
    {3, 4, 5, 6, 7},
    {8}
};

内存图关键点(常考画图题):

jagged → [引用] → { [引用], [引用], [引用] }
                  ↓       ↓       ↓
                {1,2}   {3,4,5,6,7}  {8}

5. 数组常用操作(必会)

操作代码示例时间复杂度说明
长度arr.lengthO(1)属性,不是方法!
遍历(推荐)for(int num : arr)O(n)增强for循环(只读最安全)
普通for遍历for(int i=0; i<arr.length; i++)O(n)需要下标时使用
打印Arrays.toString(arr)必须 import java.util.Arrays
排序Arrays.sort(arr)O(n log n)基本类型快排 / 对象需实现Comparable
二分查找(有序)Arrays.binarySearch(arr, key)O(log n)必须先排序!负数表示插入点
填充Arrays.fill(arr, 0)O(n)全部填充同一个值
复制Arrays.copyOf(arr, newLength)O(n)产生新数组
比较Arrays.equals(arr1, arr2)O(n)内容比较(不是 == )
深比较(多维)Arrays.deepEquals(arr1, arr2)O(n)多维数组专用

6. 常见坑 & 最佳实践(2025–2026 面试重灾区)

排名坑 / 错误做法正确 / 推荐做法为什么重要(后果)
1int[] a = new int[5]; a[5] = 1;下标永远 < lengthArrayIndexOutOfBoundsException
2直接用 == 比较两个数组Arrays.equals()Arrays.deepEquals()== 比较的是引用地址
3String[] strs = {"a","b"}; strs.length()strs.length(属性!)编译错误
4大量使用 new int[1000000] 循环创建尽可能复用数组 + Arrays.fill()频繁GC、内存碎片
5多维数组不规则时直接 matrix[i][j]先判断 matrix[i] != null && j < matrix[i].lengthNullPointerException 或越界
6Arrays.asList() 后调用 add/removenew ArrayList<>(Arrays.asList(...)) 或 List.of()UnsupportedOperationException
7基本类型数组转 ListArrays.stream(arr).boxed().toList() (Java 16+)否则只能手动循环
8认为数组长度可变需要变长 → 用 ArrayList / LinkedList数组天生固定长度
9大数组直接 System.out.println(arr)永远用 Arrays.toString() / deepToString()只打印 hashCode

7. 数组 vs ArrayList(选择依据表,面试必问)

维度数组 (int[] / String[])ArrayList / ArrayList选择建议(2026主流)
长度固定动态长度确定 → 数组;不确定 → List
性能(访问)最快(O(1),无装箱)稍慢(有装箱/拆箱)高性能场景优先数组
内存占用更省(连续 + 无额外对象头)更多(每个元素包装成对象)大数据量优先数组
方法丰富度极少丰富(add/remove/contains/indexOf 等)频繁操作选 List
泛型支持不支持支持需要泛型 → List
多线程安全非线程安全非线程安全(但有 Collections.synchronizedList)多线程慎用两者

2026 年真实趋势

  • 数值计算、性能敏感场景(游戏、科学计算、算法题) → 优先原生数组
  • 业务代码、集合操作频繁 → 几乎全用 ArrayList / List.of() / Arrays.asList()(只读场景)

8. 经典面试手写题(建议全部手敲一遍)

  1. 反转数组(原地 / 新数组两种)
  2. 找出数组中出现次数最多的元素(HashMap / 排序后统计)
  3. 二维数组顺时针旋转 90°
  4. 杨辉三角(前 n 行)
  5. 合并两个有序数组(原地合并到第一个数组)
  6. 删除有序数组中的重复元素(返回新长度)
  7. 寻找峰值(二分法 O(log n))

需要哪一道题的详细代码 + 复杂度分析 + 边界case?或者想看某个具体场景的完整示例(排序 + 搜索 + 多维 + 性能对比)?告诉我,我可以继续展开。

文章已创建 5245

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部