Java数据结构之数组
一、什么是数组?
数组是一种线性数据结构,用于存储相同类型的元素的固定大小的集合。
在 Java 中,数组本质上是一个对象,它存储一组连续的内存空间,用于存放相同类型的元素,并通过索引(index)来访问这些元素。
int[] arr = new int[5]; // 声明一个长度为5的整型数组
二、数组的基本特点
特性 | 说明 |
---|---|
类型固定 | 数组中的所有元素必须是同一类型(或其子类型)。 |
长度固定 | 一旦创建,长度不可改变(不可动态扩容)。 |
索引从0开始 | 第一个元素索引为 0 ,最后一个为 length - 1 。 |
连续内存 | 元素在内存中是连续存储的,利于缓存访问。 |
引用类型 | 数组是对象,即使元素是基本类型,数组本身也是堆上的对象。 |
三、数组的声明与创建
1. 声明方式(两种等价写法)
int[] arr; // 推荐:更清晰地表达“arr 是一个 int 数组”
int arr[]; // C 风格,不推荐
2. 创建方式
3.2.1动态初始化(指定长度)
int[] arr = new int[10]; // 创建10个int,默认值0
String[] strs = new String[5]; // 5个null引用
3.2.2静态初始化(直接赋值)
int[] arr = {1, 2, 3, 4, 5};
String[] names = {"Alice", "Bob", "Charlie"};
注意:静态初始化时不能指定长度,由编译器推断。
3.2.3动态初始化后赋值
int[] arr = new int[3];
arr[0] = 10;
arr[1] = 20;
arr[2] = 30;
四、内存模型(深入理解)
JVM 中数组的存储结构
int[] arr = new int[4];
在 JVM 堆(Heap)中分配一块连续的空间:
arr
是一个引用变量,存放在栈上。- 实际的数组对象在堆上分配。
- 每个元素占据固定字节(如
int
占 4 字节),所以可以随机访问(Random Access)。
正因为连续存储 + 固定大小,所以可以通过
base_address + index * element_size
快速定位元素。
五、多维数组(其实是数组的数组)
Java 中的多维数组不是真正的“二维表”,而是数组的数组。
int[][] matrix = new int[3][4]; // 3行4列的二维数组
这相当于创建了一个长度为3的一维数组,每个元素是一个长度为4的 int[]
。也可以是不规则数组(Jagged Array):
int[][] jagged = new int[3][];
jagged[0] = new int[2];
jagged[1] = new int[5];
jagged[2] = new int[3];
六、数组的常用操作
操作 | 示例 |
---|---|
访问元素 | arr[0] |
修改元素 | arr[1] = 100; |
获取长度 | arr.length (注意:不是 length() 方法) |
遍历 | for , for-each , Arrays.stream() |
复制 | System.arraycopy() , Arrays.copyOf() |
排序 | Arrays.sort(arr) |
查找 | Arrays.binarySearch() (需先排序) |
转字符串 | Arrays.toString(arr) |
示例:遍历
int[] arr = {1, 2, 3, 4, 5};// 方式1:普通for
for (int i = 0; i < arr.length; i++) {System.out.println(arr[i]);
}// 方式2:增强for(for-each)
for (int value : arr) {System.out.println(value);
}// 方式3:Stream(Java 8+)
Arrays.stream(arr).forEach(System.out::println);
七、Arrays 工具类(java.util.Arrays)
这是处理数组的利器,封装了常用操作:
import java.util.Arrays;int[] arr = {5, 2, 8, 1};Arrays.sort(arr); // 排序:[1,2,5,8]
int index = Arrays.binarySearch(arr, 5); // 二分查找,返回索引
int[] copy = Arrays.copyOf(arr, 10); // 扩容复制
boolean equals = Arrays.equals(arr1, arr2);
String str = Arrays.toString(arr); // 输出:[1, 2, 5, 8]
八、数组的优缺点
优点 | 缺点 |
---|---|
支持随机访问(O(1)) | 长度固定,无法动态扩容 |
内存连续,缓存友好 | 插入/删除效率低(O(n)) |
实现简单,性能高 | 类型单一,功能有限 |
是很多数据结构的基础(如 ArrayList 底层就是数组) | 不支持泛型(原始类型数组) |
九、数组 vs ArrayList
对比项 | 数组(Array) | ArrayList |
---|---|---|
大小 | 固定 | 动态可变 |
类型 | 可存基本类型 | 只能存对象(包装类) |
泛型 | 不支持 | 支持 |
方法 | 少(length属性) | 丰富(add, remove, size等) |
性能 | 更快(直接内存访问) | 稍慢(封装开销) |
内存 | 节省 | 多一些(对象头、扩容) |
ArrayList 底层就是基于数组实现的,它通过扩容机制(通常是1.5倍)解决数组长度固定的问题。
十、常见&易错点
length
vslength()
vssize()
- 数组:
arr.length
(属性,不是方法) - 字符串:
str.length()
- 集合:
list.size()
- 数组:
数组越界异常
int[] arr = new int[3]; System.out.println(arr[3]); // ❌ 抛出 ArrayIndexOutOfBoundsException
空指针异常
int[] arr = null; System.out.println(arr.length); // ❌ NullPointerException
深拷贝 vs 浅拷贝
- 基本类型数组:
Arrays.copyOf
是深拷贝 - 引用类型数组:需手动深拷贝每个对象
- 基本类型数组:
最后总结:数组的核心要点
- 数组是固定大小、连续内存、同类型的集合。
- 是 Java 中最基础的数据结构,访问快(O(1)),但增删慢(O(n))。
- 多维数组是“数组的数组”。
- 推荐使用
java.util.Arrays
工具类进行操作。 - 虽然功能有限,但它是
ArrayList
、HashMap
等集合类的底层基础。