Java 数组详解
一、数组概述
- 定义:数组是 Java 中一种用于存储固定数量、相同类型数据的有序集合。
- 特点:
- 数组在内存中是连续存储的。
- 数组的长度在创建时确定,不可动态改变。
- 数组是对象,存储在堆内存中(基本类型数组的值直接存储在数组中,引用类型数组存储的是对象的引用)。
二、数组的声明与初始化
- 声明数组:
- 格式:
数据类型[] 数组名;
或数据类型 数组名[];
(两种写法等价)。 - 示例:
java int[] numbers; // 推荐写法 String names[]; // 另一种写法
- 初始化数组:
- 静态初始化:在声明时直接初始化数组元素。
java int[] arr1 = {1, 2, 3, 4, 5}; String[] arr2 = {"Java", "Python", "C++"};
- 动态初始化:先声明数组长度,再赋值。
java int[] arr3 = new int[5]; // 长度为 5,默认初始化为 0 String[] arr4 = new String[3]; // 长度为 3,默认初始化为 null
- 匿名数组:
- 直接创建并使用数组,不声明变量名。
- 示例:
java System.out.println(new int[]{10, 20, 30}[1]); // 输出 20
三、数组的基本操作
- 访问数组元素:
- 通过索引访问,索引从
0
开始。 - 示例:
java int[] arr = {10, 20, 30}; System.out.println(arr[0]); // 输出 10 arr[1] = 50; // 修改第二个元素
- 数组长度:
- 使用
length
属性获取数组长度。 - 示例:
java int[] arr = {1, 2, 3}; System.out.println(arr.length); // 输出 3
- 遍历数组:
- for 循环:
java int[] arr = {1, 2, 3, 4, 5}; for (int i = 0; i < arr.length; i++) { System.out.print(arr[i] + " "); // 输出 1 2 3 4 5 }
- 增强 for 循环(for-each):
java for (int num : arr) { System.out.print(num + " "); // 输出 1 2 3 4 5 }
- 数组复制:
System.arraycopy
:java int[] src = {1, 2, 3, 4, 5}; int[] dest = new int[5]; System.arraycopy(src, 0, dest, 0, src.length); // 从 src 复制到 dest
Arrays.copyOf
:java int[] newArr = Arrays.copyOf(src, src.length); // 复制整个数组 int[] extendedArr = Arrays.copyOf(src, 10); // 扩展数组,多出的位置用默认值填充
clone
方法:java int[] clonedArr = src.clone(); // 浅拷贝
四、多维数组
- 二维数组:
- 声明和初始化:
int[][] matrix = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }; int[][] matrix2 = new int[3][3]; // 3 行 3 列,默认初始化为 0
- 访问元素:
java System.out.println(matrix[1][2]); // 输出 6(第二行第三列)
- 不规则二维数组(锯齿数组):
java int[][] jaggedArray = new int[3][]; jaggedArray[0] = new int[2]; // 第一行 2 列 jaggedArray[1] = new int[3]; // 第二行 3 列 jaggedArray[2] = new int[1]; // 第三行 1 列
- 多维数组:
- Java 支持更高维度的数组,但实际开发中很少使用。
- 示例(三维数组):
java int[][][] cube = new int[2][2][2]; // 2x2x2 的三维数组
五、数组的常用方法(java.util.Arrays
)
Arrays
类提供了许多静态方法用于操作数组:
- 排序:
int[] arr = {5, 2, 8, 1, 9};
Arrays.sort(arr); // 升序排序
System.out.println(Arrays.toString(arr)); // [1, 2, 5, 8, 9]
- 查找:
- 二分查找(数组必须已排序):
java int index = Arrays.binarySearch(arr, 5); // 返回 2(5 的索引)
- 填充:
Arrays.fill(arr, 0); // 将所有元素填充为 0
- 比较:
int[] arr1 = {1, 2, 3};
int[] arr2 = {1, 2, 3};
System.out.println(Arrays.equals(arr1, arr2)); // true
- 转换为字符串:
System.out.println(Arrays.toString(arr)); // 输出数组内容
六、数组与集合的对比
特性 | 数组 | 集合(如 ArrayList ) |
---|---|---|
长度 | 固定,创建时确定 | 动态,可自动扩容 |
存储类型 | 必须相同类型 | 可以存储不同类型(通过泛型限制) |
性能 | 访问速度快(索引直接计算) | 访问稍慢(需遍历) |
功能 | 功能较少 | 功能丰富(如排序、过滤等) |
适用场景 | 已知数据量且固定 | 数据量不确定或需要频繁操作 |
七、数组的注意事项
- 数组越界:
- 访问不存在的索引会抛出
ArrayIndexOutOfBoundsException
。 - 示例:
java int[] arr = {1, 2, 3}; System.out.println(arr[3]); // 抛出异常
- 空指针异常:
- 访问未初始化的数组或数组中的
null
元素会抛出NullPointerException
。 - 示例:
String[] arr = null; System.out.println(arr[0]); // 抛出 NullPointerException String[] arr2 = new String[2]; System.out.println(arr2[0].length()); // 抛出 NullPointerException
- 浅拷贝问题:
- 数组复制时,如果是引用类型数组,复制的是引用而非对象本身。
- 示例:
String[] original = {"A", "B"}; String[] copy = original.clone(); copy[0] = "C"; // 不会影响 original // 引用类型数组的浅拷贝问题 Person[] people1 = {new Person("Alice"), new Person("Bob")}; Person[] people2 = people1.clone(); people2[0].setName("Charlie"); // 会影响 people1 中的对象
八、数组的实际应用
- 作为方法参数:
- 数组可以作为方法的参数传递。
- 示例:
public static void printArray(int[] arr) { for (int num : arr) { System.out.print(num + " "); } } public static void main(String[] args) { int[] numbers = {1, 2, 3}; printArray(numbers); // 输出 1 2 3 }
- 作为方法返回值:
- 方法可以返回数组。
- 示例:
public static int[] createArray() { return new int[]{10, 20, 30}; } public static void main(String[] args) { int[] arr = createArray(); System.out.println(Arrays.toString(arr)); // [10, 20, 30] }
- 命令行参数:
main
方法的参数String[] args
用于接收命令行参数。- 示例:
java public class Main { public static void main(String[] args) { for (String arg : args) { System.out.println(arg); } } }
运行命令:java Main Hello World
输出:Hello World
九、总结
- 数组是 Java 中存储固定数量、相同类型数据的基础数据结构。
- 数组的长度在创建时确定,不可动态改变。
- 数组支持索引访问,索引从 0 开始。
- 多维数组可以表示矩阵或表格数据。
Arrays
类提供了丰富的工具方法用于操作数组。- 在需要动态扩容或复杂操作时,建议使用集合类(如
ArrayList
)。
十、示例代码
import java.util.Arrays;
public class ArrayExample {
public static void main(String[] args) {
// 一维数组
int[] numbers = {10, 20, 30, 40, 50};
System.out.println("数组长度: " + numbers.length); // 5
System.out.println("遍历数组:");
for (int num : numbers) {
System.out.print(num + " "); // 10 20 30 40 50
}
System.out.println();
// 二维数组
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
System.out.println("二维数组:");
for (int[] row : matrix) {
System.out.println(Arrays.toString(row));
}
// Arrays 类方法
Arrays.sort(numbers); // 排序
System.out.println("排序后: " + Arrays.toString(numbers)); // [10, 20, 30, 40, 50]
System.out.println("查找 30 的索引: " + Arrays.binarySearch(numbers, 30)); // 2
// 数组复制
int[] copy = Arrays.copyOf(numbers, numbers.length);
System.out.println("复制后的数组: " + Arrays.toString(copy)); // [10, 20, 30, 40, 50]
}
}
输出:
数组长度: 5
遍历数组:
10 20 30 40 50
二维数组:
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
排序后: [10, 20, 30, 40, 50]
查找 30 的索引: 2
复制后的数组: [10, 20, 30, 40, 50]
通过以上内容,可以全面了解 Java 数组的声明、初始化、操作、多维数组、常用方法以及实际应用场景。