Java 数组(Array)超详细讲解
(从零基础到面试八股 + 内存原理 + 常见坑 + 最佳实践)
数组是 Java 中最基础、最重要的数据结构之一,几乎所有集合框架(ArrayList、HashMap 等)底层都依赖数组。掌握数组,才能真正理解 Java 内存模型和性能优化。
1. 什么是数组?
数组是相同数据类型的有序集合,在内存中分配连续的存储空间。
特点:
- 长度固定(一旦创建,不可改变)
- 元素类型必须一致
- 下标从 0 开始
- 支持随机访问(通过下标,时间复杂度 O(1))
2. 数组的定义方式(三种写法)
方式一:先声明再创建(推荐初学者使用)
// 1. 声明
int[] arr1; // 最常用
int arr2[]; // C语言风格,不推荐
// 2. 创建(分配空间)
arr1 = new int[5]; // 创建长度为5的int数组,默认值全为0
方式二:声明 + 创建 + 初始化(静态初始化)
// 静态初始化(最常用)
int[] arr = {10, 20, 30, 40, 50};
// 等价于
int[] arr = new int[]{10, 20, 30, 40, 50};
方式三:动态初始化(先创建,后赋值)
int[] arr = new int[5]; // 默认值:0
arr[0] = 100;
arr[1] = 200;
// ...
3. 数组的常用操作
public class ArrayDemo {
public static void main(String[] args) {
int[] scores = {85, 92, 78, 96, 88};
// 1. 获取长度
System.out.println("数组长度: " + scores.length); // 5
// 2. 访问元素(下标从0开始)
System.out.println(scores[0]); // 85
System.out.println(scores[4]); // 88
// 3. 修改元素
scores[2] = 80;
// 4. 遍历数组(三种方式)
// 方式1:普通for循环
for (int i = 0; i < scores.length; i++) {
System.out.print(scores[i] + " ");
}
System.out.println();
// 方式2:增强for循环(foreach,最常用)
for (int score : scores) {
System.out.print(score + " ");
}
System.out.println();
// 方式3:JDK 8+ Stream(函数式)
Arrays.stream(scores).forEach(System.out::println);
}
}
4. 数组的内存结构(面试高频!)
int[] arr = new int[3];
arr[0] = 10;
arr[1] = 20;
内存指向图解:
栈(Stack) 堆(Heap)
arr ─────────────────────► [10, 20, 0] ← 连续内存空间
引用(地址) ↑
arr[0] arr[1] arr[2]
- 数组变量(引用)存储在栈中,保存的是堆中数组的首地址。
- 数组元素存储在堆中,内存连续。
- 数组一旦创建,长度固定,类型固定。
5. 数组的默认初始化值
| 数组元素类型 | 默认值 |
|---|---|
| 基本类型 int | 0 |
| 基本类型 double | 0.0 |
| 基本类型 char | ” |
| 基本类型 boolean | false |
| 引用类型 | null |
6. 多维数组(重点)
Java 中没有真正的多维数组,本质是数组的数组。
// 二维数组
int[][] matrix = new int[3][4]; // 3行4列
// 静态初始化
int[][] arr = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// 不规则二维数组(每行长度可不同)
int[][] irregular = new int[3][];
irregular[0] = new int[2];
irregular[1] = new int[5];
irregular[2] = new int[3];
7. 数组的常见工具类 —— Arrays
int[] arr = {5, 2, 8, 1, 9};
// 1. 排序
Arrays.sort(arr); // [1,2,5,8,9]
// 2. 二分查找(必须先排序)
int index = Arrays.binarySearch(arr, 5);
// 3. 填充
Arrays.fill(arr, 100);
// 4. 数组转字符串(打印用)
System.out.println(Arrays.toString(arr));
// 5. 数组拷贝
int[] newArr = Arrays.copyOf(arr, 10); // 扩容
8. 数组的常见问题与坑(生产/面试必知)
- 数组越界异常(ArrayIndexOutOfBoundsException)
arr[arr.length]; // 错误!最大下标是 length-1
- 数组是定长的,无法直接扩容
- 需要手动拷贝到新数组(Arrays.copyOf 底层就是这么做的)
- 数组作为方法参数时,传递的是引用(可修改元素,但不能改变数组长度)
- null 指针异常
int[] arr = null;
System.out.println(arr.length); // 报错!
9. 数组 vs 集合(ArrayList)对比(面试常问)
| 维度 | 数组(Array) | ArrayList |
|---|---|---|
| 长度 | 固定 | 动态可变 |
| 性能 | 更高(连续内存) | 稍低(涉及扩容) |
| 类型安全 | 必须相同类型 | 泛型,更安全 |
| 操作方便性 | 一般 | 丰富(add、remove等) |
| 适用场景 | 已知固定大小、高性能 | 大部分业务场景 |
规则:
- 已知元素数量且固定 → 用数组
- 元素数量不确定、需要频繁增删 → 用 ArrayList
10. 练习题(建议立即动手)
- 定义一个 int 数组,存放 1-10,求和、求平均值
- 冒泡排序实现
- 找出数组中最大值和最小值
- 数组去重(不使用 Set)
- 二维数组转一维数组
数组部分总结口诀:
数组定长类型同,内存连续下标零;
栈存引用堆存值,越界异常要小心;
静态动态两种初始化,Arrays工具很给力;
长度固定要扩容,拷贝新数组来完成。
数组是 Java 所有集合的底层基础,学透数组,后续学习 List、Map、Set 会非常轻松。
想继续学习哪一部分?
- 「下一节:Java 集合框架全解析(List、Set、Map)」
- 「数组与指针(内存模型深入)」
- 「数组常见面试题 20 道 + 答案」
- 「二维数组 + 不规则数组实战」
- 或直接进入「Java 面向对象进阶」
直接回复关键词,我立刻给你下一篇超详细整理!
继续加油!数组掌握好了,Java 基础就稳了一大半!