Skip to content

数组

数组是一种数据结构,用于存储相同类型的多个元素。在Java中,数组是引用类型,它具有固定的大小,一旦创建就不能改变。

数组的基本概念

什么是数组?

数组是相同类型数据的有序集合,它有以下特点:

  • 数组中的元素具有相同的数据类型
  • 数组的大小是固定的,一旦创建就不能改变
  • 数组中的元素在内存中是连续存储的
  • 数组元素可以通过索引访问,索引从0开始

数组的用途

  • 存储大量相同类型的数据
  • 实现列表、栈、队列等数据结构
  • 高效地访问和操作数据集合

一维数组

数组的声明

在Java中,有两种声明数组的方式:

java
// 方式1:数据类型[] 数组名;
int[] numbers;

// 方式2:数据类型 数组名[];
int scores[];

推荐使用第一种方式,因为它更清晰地表示数组是一个引用类型。

数组的初始化

数组的初始化有三种方式:

1. 静态初始化

在声明数组的同时为数组元素赋值。

java
// 静态初始化
int[] numbers = {1, 2, 3, 4, 5};
String[] names = {"张三", "李四", "王五"};

2. 动态初始化

先声明数组,然后指定数组的大小,Java会为数组元素分配默认值。

java
// 动态初始化
int[] numbers = new int[5]; // 创建一个包含5个int类型元素的数组
// 默认值为0

String[] names = new String[3]; // 创建一个包含3个String类型元素的数组
// 默认值为null

3. 分步初始化

先声明数组,然后分配内存空间,最后为元素赋值。

java
// 分步初始化
int[] numbers;
numbers = new int[5]; // 分配内存空间
numbers[0] = 1; // 为元素赋值
numbers[1] = 2;
numbers[2] = 3;
numbers[3] = 4;
numbers[4] = 5;

数组元素的访问

数组元素通过索引访问,索引从0开始,到数组长度-1结束。

java
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 属性可以获取数组的长度(元素个数)。

java
int[] numbers = {1, 2, 3, 4, 5};
int length = numbers.length;
System.out.println("数组长度: " + length); // 输出: 数组长度: 5

数组的遍历

遍历数组是指依次访问数组中的每个元素。有以下几种方式:

1. 使用 for 循环遍历

java
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)遍历

java
int[] numbers = {1, 2, 3, 4, 5};

for (int num : numbers) {
    System.out.println("元素: " + num);
}

3. 使用 Arrays 类的 toString() 方法

java
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, long0
float, double0.0
char'\u0000' (空字符)
booleanfalse
引用类型null
java
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支持多维数组,最常见的是二维数组。多维数组实际上是数组的数组。

二维数组的声明

java
// 方式1
int[][] matrix;

// 方式2
int matrix[][];

二维数组的初始化

1. 静态初始化

java
int[][] matrix = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

2. 动态初始化

java
// 创建3行4列的二维数组
int[][] matrix = new int[3][4];

3. 不规则二维数组

Java允许创建不规则的二维数组(每行的列数不同)。

java
// 创建不规则二维数组
int[][] irregularMatrix = new int[3][];
irregularMatrix[0] = new int[2]; // 第一行有2列
irregularMatrix[1] = new int[3]; // 第二行有3列
irregularMatrix[2] = new int[4]; // 第三行有4列

二维数组元素的访问

java
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 属性表示该行的列数
java
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 循环

java
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 循环

java
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() 方法

java
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() 方法可以对数组进行排序。

java
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() 方法可以在已排序的数组中二分查找指定元素。

java
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() 方法

java
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() 方法

java
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() 方法

java
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() 方法可以将数组的所有元素或指定范围的元素设置为指定值。

java
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() 方法可以比较两个数组是否相等(长度相同且对应位置的元素相等)。

java
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)

当访问数组的无效索引(负数或大于等于数组长度的索引)时抛出。

java
int[] numbers = {1, 2, 3};
// System.out.println(numbers[3]); // 抛出 ArrayIndexOutOfBoundsException
// System.out.println(numbers[-1]); // 抛出 ArrayIndexOutOfBoundsException

2. 空指针异常(NullPointerException)

当尝试访问未初始化的数组的元素时抛出。

java
int[] numbers = null;
// System.out.println(numbers[0]); // 抛出 NullPointerException

3. 数组初始化错误

java
// 错误:声明时不能指定数组大小
// int[5] numbers;

// 错误:静态初始化时不能指定数组大小
// int[5] numbers = {1, 2, 3, 4, 5};

// 正确:动态初始化
int[] numbers = new int[5];

4. 数组是引用类型

数组是引用类型,将一个数组变量赋值给另一个数组变量,会导致两个变量引用同一个数组。

java
int[] array1 = {1, 2, 3};
int[] array2 = array1; // array2 引用 array1 指向的数组

array2[0] = 100;
System.out.println(array1[0]); // 输出: 100,因为两个变量引用同一个数组

5. 数组的不可变性

数组的大小一旦创建就不能改变,如果需要动态改变大小,应该使用集合类(如ArrayList)。

数组的应用场景

  1. 存储固定数量的数据:当你知道需要存储的数据数量固定时
  2. 高效的数据访问:数组提供O(1)时间复杂度的数据访问
  3. 数值计算:科学计算、统计分析等
  4. 实现其他数据结构:如栈、队列、哈希表等
  5. 多维数据表示:如图像、矩阵等

小结

  • 数组是存储相同类型元素的固定大小的集合
  • 数组在Java中是引用类型,创建后大小不能改变
  • 数组的索引从0开始,到length-1结束
  • 数组有一维数组和多维数组之分
  • 数组的初始化方式有静态初始化、动态初始化和分步初始化
  • 可以使用循环或增强for循环遍历数组
  • Arrays类提供了许多用于操作数组的静态方法
  • 常见的数组操作包括排序、查找、复制和填充等

数组是Java编程中最基本的数据结构之一,掌握数组的使用对于编写高效的程序至关重要。