数组
数组是一种数据结构,用于存储相同类型的多个元素。在Java中,数组是引用类型,它具有固定的大小,一旦创建就不能改变。
数组的基本概念
什么是数组?
数组是相同类型数据的有序集合,它有以下特点:
- 数组中的元素具有相同的数据类型
- 数组的大小是固定的,一旦创建就不能改变
- 数组中的元素在内存中是连续存储的
- 数组元素可以通过索引访问,索引从0开始
数组的用途
- 存储大量相同类型的数据
- 实现列表、栈、队列等数据结构
- 高效地访问和操作数据集合
一维数组
数组的声明
在Java中,有两种声明数组的方式:
// 方式1:数据类型[] 数组名;
int[] numbers;
// 方式2:数据类型 数组名[];
int scores[];推荐使用第一种方式,因为它更清晰地表示数组是一个引用类型。
数组的初始化
数组的初始化有三种方式:
1. 静态初始化
在声明数组的同时为数组元素赋值。
// 静态初始化
int[] numbers = {1, 2, 3, 4, 5};
String[] names = {"张三", "李四", "王五"};2. 动态初始化
先声明数组,然后指定数组的大小,Java会为数组元素分配默认值。
// 动态初始化
int[] numbers = new int[5]; // 创建一个包含5个int类型元素的数组
// 默认值为0
String[] names = new String[3]; // 创建一个包含3个String类型元素的数组
// 默认值为null3. 分步初始化
先声明数组,然后分配内存空间,最后为元素赋值。
// 分步初始化
int[] numbers;
numbers = new int[5]; // 分配内存空间
numbers[0] = 1; // 为元素赋值
numbers[1] = 2;
numbers[2] = 3;
numbers[3] = 4;
numbers[4] = 5;数组元素的访问
数组元素通过索引访问,索引从0开始,到数组长度-1结束。
int[] numbers = {10, 20, 30, 40, 50};
System.out.println(numbers[0]); // 输出: 10
System.out.println(numbers[2]); // 输出: 30
// 修改数组元素
numbers[1] = 25;
System.out.println(numbers[1]); // 输出: 25数组的长度
使用数组的 length 属性可以获取数组的长度(元素个数)。
int[] numbers = {1, 2, 3, 4, 5};
int length = numbers.length;
System.out.println("数组长度: " + length); // 输出: 数组长度: 5数组的遍历
遍历数组是指依次访问数组中的每个元素。有以下几种方式:
1. 使用 for 循环遍历
int[] numbers = {1, 2, 3, 4, 5};
for (int i = 0; i < numbers.length; i++) {
System.out.println("元素[" + i + "]: " + numbers[i]);
}2. 使用增强 for 循环(for-each)遍历
int[] numbers = {1, 2, 3, 4, 5};
for (int num : numbers) {
System.out.println("元素: " + num);
}3. 使用 Arrays 类的 toString() 方法
import java.util.Arrays;
int[] numbers = {1, 2, 3, 4, 5};
System.out.println(Arrays.toString(numbers)); // 输出: [1, 2, 3, 4, 5]数组的默认值
当创建数组但未为元素赋值时,Java会为元素分配默认值:
| 数据类型 | 默认值 |
|---|---|
| byte, short, int, long | 0 |
| float, double | 0.0 |
| char | '\u0000' (空字符) |
| boolean | false |
| 引用类型 | null |
int[] intArray = new int[3]; // [0, 0, 0]
double[] doubleArray = new double[3]; // [0.0, 0.0, 0.0]
boolean[] booleanArray = new boolean[3]; // [false, false, false]
String[] stringArray = new String[3]; // [null, null, null]多维数组
Java支持多维数组,最常见的是二维数组。多维数组实际上是数组的数组。
二维数组的声明
// 方式1
int[][] matrix;
// 方式2
int matrix[][];二维数组的初始化
1. 静态初始化
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};2. 动态初始化
// 创建3行4列的二维数组
int[][] matrix = new int[3][4];3. 不规则二维数组
Java允许创建不规则的二维数组(每行的列数不同)。
// 创建不规则二维数组
int[][] irregularMatrix = new int[3][];
irregularMatrix[0] = new int[2]; // 第一行有2列
irregularMatrix[1] = new int[3]; // 第二行有3列
irregularMatrix[2] = new int[4]; // 第三行有4列二维数组元素的访问
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
System.out.println(matrix[0][0]); // 输出: 1
System.out.println(matrix[1][2]); // 输出: 6
// 修改元素
matrix[2][1] = 88;
System.out.println(matrix[2][1]); // 输出: 88二维数组的长度
- 二维数组的
length属性表示行数 - 每一行数组的
length属性表示该行的列数
int[][] matrix = {
{1, 2, 3},
{4, 5},
{6, 7, 8, 9}
};
System.out.println("行数: " + matrix.length); // 输出: 行数: 3
System.out.println("第一行列数: " + matrix[0].length); // 输出: 第一行列数: 3
System.out.println("第二行列数: " + matrix[1].length); // 输出: 第二行列数: 2
System.out.println("第三行列数: " + matrix[2].length); // 输出: 第三行列数: 4二维数组的遍历
1. 使用嵌套 for 循环
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
System.out.print(matrix[i][j] + " ");
}
System.out.println();
}2. 使用增强 for 循环
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
for (int[] row : matrix) {
for (int element : row) {
System.out.print(element + " ");
}
System.out.println();
}3. 使用 Arrays 类的 deepToString() 方法
import java.util.Arrays;
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
System.out.println(Arrays.deepToString(matrix));
// 输出: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]数组的常见操作
Java 提供了 java.util.Arrays 类,包含了许多操作数组的静态方法。
数组的排序
使用 Arrays.sort() 方法可以对数组进行排序。
import java.util.Arrays;
int[] numbers = {5, 2, 9, 1, 5, 6};
Arrays.sort(numbers);
System.out.println(Arrays.toString(numbers)); // 输出: [1, 2, 5, 5, 6, 9]
String[] names = {"张三", "李四", "王五", "赵六"};
Arrays.sort(names); // 按字典顺序排序
System.out.println(Arrays.toString(names)); // 输出: [李四, 王五, 张三, 赵六]数组的查找
使用 Arrays.binarySearch() 方法可以在已排序的数组中二分查找指定元素。
import java.util.Arrays;
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int index = Arrays.binarySearch(numbers, 6);
System.out.println("元素6的索引: " + index); // 输出: 元素6的索引: 5
index = Arrays.binarySearch(numbers, 10);
System.out.println("元素10的索引: " + index); // 输出负数,表示未找到数组的复制
有几种方式可以复制数组:
1. 使用 Arrays.copyOf() 方法
import java.util.Arrays;
int[] source = {1, 2, 3, 4, 5};
int[] dest = Arrays.copyOf(source, 3); // 复制前3个元素
System.out.println(Arrays.toString(dest)); // 输出: [1, 2, 3]
int[] expanded = Arrays.copyOf(source, 7); // 复制并扩展数组
System.out.println(Arrays.toString(expanded)); // 输出: [1, 2, 3, 4, 5, 0, 0]2. 使用 Arrays.copyOfRange() 方法
import java.util.Arrays;
int[] source = {1, 2, 3, 4, 5};
int[] dest = Arrays.copyOfRange(source, 1, 4); // 复制索引1到3的元素(不包括4)
System.out.println(Arrays.toString(dest)); // 输出: [2, 3, 4]3. 使用 System.arraycopy() 方法
int[] source = {1, 2, 3, 4, 5};
int[] dest = new int[5];
// 参数: 源数组, 源数组起始位置, 目标数组, 目标数组起始位置, 复制元素个数
System.arraycopy(source, 0, dest, 0, source.length);
for (int i = 0; i < dest.length; i++) {
System.out.print(dest[i] + " ");
} // 输出: 1 2 3 4 5数组的填充
使用 Arrays.fill() 方法可以将数组的所有元素或指定范围的元素设置为指定值。
import java.util.Arrays;
int[] numbers = new int[5];
Arrays.fill(numbers, 10); // 填充所有元素为10
System.out.println(Arrays.toString(numbers)); // 输出: [10, 10, 10, 10, 10]
int[] rangeNumbers = new int[5];
Arrays.fill(rangeNumbers, 1, 4, 20); // 填充索引1到3的元素为20
System.out.println(Arrays.toString(rangeNumbers)); // 输出: [0, 20, 20, 20, 0]数组的比较
使用 Arrays.equals() 方法可以比较两个数组是否相等(长度相同且对应位置的元素相等)。
import java.util.Arrays;
int[] array1 = {1, 2, 3, 4, 5};
int[] array2 = {1, 2, 3, 4, 5};
int[] array3 = {1, 2, 3, 4, 6};
System.out.println(Arrays.equals(array1, array2)); // 输出: true
System.out.println(Arrays.equals(array1, array3)); // 输出: false
// 对于多维数组,使用 deepEquals() 方法
int[][] matrix1 = {{1, 2}, {3, 4}};
int[][] matrix2 = {{1, 2}, {3, 4}};
System.out.println(Arrays.deepEquals(matrix1, matrix2)); // 输出: true数组与集合的区别
Java提供了数组和集合(Collection)两种存储数据的方式,它们有以下区别:
| 特性 | 数组 | 集合 |
|---|---|---|
| 大小 | 固定 | 动态可变 |
| 类型 | 可以存储基本类型和引用类型 | 只能存储引用类型(Java 5+自动装箱/拆箱) |
| 效率 | 访问效率高 | 操作更灵活,但效率稍低 |
| 功能 | 功能较少 | 提供丰富的操作方法 |
数组的常见错误与注意事项
1. 数组索引越界异常(ArrayIndexOutOfBoundsException)
当访问数组的无效索引(负数或大于等于数组长度的索引)时抛出。
int[] numbers = {1, 2, 3};
// System.out.println(numbers[3]); // 抛出 ArrayIndexOutOfBoundsException
// System.out.println(numbers[-1]); // 抛出 ArrayIndexOutOfBoundsException2. 空指针异常(NullPointerException)
当尝试访问未初始化的数组的元素时抛出。
int[] numbers = null;
// System.out.println(numbers[0]); // 抛出 NullPointerException3. 数组初始化错误
// 错误:声明时不能指定数组大小
// int[5] numbers;
// 错误:静态初始化时不能指定数组大小
// int[5] numbers = {1, 2, 3, 4, 5};
// 正确:动态初始化
int[] numbers = new int[5];4. 数组是引用类型
数组是引用类型,将一个数组变量赋值给另一个数组变量,会导致两个变量引用同一个数组。
int[] array1 = {1, 2, 3};
int[] array2 = array1; // array2 引用 array1 指向的数组
array2[0] = 100;
System.out.println(array1[0]); // 输出: 100,因为两个变量引用同一个数组5. 数组的不可变性
数组的大小一旦创建就不能改变,如果需要动态改变大小,应该使用集合类(如ArrayList)。
数组的应用场景
- 存储固定数量的数据:当你知道需要存储的数据数量固定时
- 高效的数据访问:数组提供O(1)时间复杂度的数据访问
- 数值计算:科学计算、统计分析等
- 实现其他数据结构:如栈、队列、哈希表等
- 多维数据表示:如图像、矩阵等
小结
- 数组是存储相同类型元素的固定大小的集合
- 数组在Java中是引用类型,创建后大小不能改变
- 数组的索引从0开始,到length-1结束
- 数组有一维数组和多维数组之分
- 数组的初始化方式有静态初始化、动态初始化和分步初始化
- 可以使用循环或增强for循环遍历数组
- Arrays类提供了许多用于操作数组的静态方法
- 常见的数组操作包括排序、查找、复制和填充等
数组是Java编程中最基本的数据结构之一,掌握数组的使用对于编写高效的程序至关重要。