Appearance
第4课:数组
🎯 学习目标
- 掌握一维数组的创建和使用
- 掌握多维数组
- 理解数组的内存结构
- 掌握 Arrays 工具类
📖 一、一维数组
C vs Java 数组
C 语言:
c
// C: 数组大小必须是常量
int arr[5];
arr[0] = 10;
// 动态数组需要手动管理
int* arr2 = malloc(5 * sizeof(int));
free(arr2);Java:
java
// Java: 数组大小可以是变量
int size = 5;
int[] arr = new int[size];
arr[0] = 10;
// 自动垃圾回收,无需手动释放1. 数组声明和创建
java
// 方式1:声明 + 创建
int[] numbers; // 声明
numbers = new int[5]; // 创建
// 方式2:合并
int[] numbers = new int[5];
// 方式3:声明时初始化
int[] numbers = {1, 2, 3, 4, 5};
// 方式4:new + 初始化
int[] numbers = new int[]{1, 2, 3, 4, 5};
// 注意:Java 推荐 int[] arr,而不是 int arr[]2. 数组访问
java
int[] arr = {10, 20, 30, 40, 50};
// 访问元素
int first = arr[0]; // 10
int last = arr[4]; // 50
// 修改元素
arr[0] = 100;
// 获取长度
int length = arr.length; // 5(属性,不是方法)
// 遍历
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
// 增强 for 循环
for (int num : arr) {
System.out.println(num);
}3. 数组默认值
java
int[] intArr = new int[3]; // [0, 0, 0]
double[] doubleArr = new double[3]; // [0.0, 0.0, 0.0]
boolean[] boolArr = new boolean[3]; // [false, false, false]
String[] strArr = new String[3]; // [null, null, null]4. 数组越界
java
int[] arr = {1, 2, 3};
System.out.println(arr[5]); // ❌ ArrayIndexOutOfBoundsException
// Java 会检查越界(比 C 安全)📖 二、多维数组
1. 二维数组
java
// 声明和创建
int[][] matrix = new int[3][4]; // 3行4列
// 初始化
int[][] matrix = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
// 访问元素
int element = matrix[1][2]; // 7
// 遍历
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();
}
// 增强 for
for (int[] row : matrix) {
for (int num : row) {
System.out.print(num + " ");
}
System.out.println();
}2. 不规则数组
java
// Java 支持不规则数组(每行长度不同)
int[][] irregular = new int[3][];
irregular[0] = new int[2];
irregular[1] = new int[3];
irregular[2] = new int[4];
// 或
int[][] irregular = {
{1, 2},
{3, 4, 5},
{6, 7, 8, 9}
};📖 三、数组操作
1. 数组复制
java
int[] source = {1, 2, 3, 4, 5};
// 方式1:循环复制
int[] copy1 = new int[source.length];
for (int i = 0; i < source.length; i++) {
copy1[i] = source[i];
}
// 方式2:System.arraycopy
int[] copy2 = new int[source.length];
System.arraycopy(source, 0, copy2, 0, source.length);
// 方式3:Arrays.copyOf
int[] copy3 = Arrays.copyOf(source, source.length);
// 方式4:clone(浅拷贝)
int[] copy4 = source.clone();2. 数组排序
java
int[] arr = {5, 2, 8, 1, 9};
// 排序
Arrays.sort(arr); // [1, 2, 5, 8, 9]
// 部分排序
Arrays.sort(arr, 1, 4); // 只排序索引1-3
// 降序(需要包装类)
Integer[] arr2 = {5, 2, 8, 1, 9};
Arrays.sort(arr2, Collections.reverseOrder());3. 数组查找
java
int[] arr = {1, 2, 5, 8, 9};
// 二分查找(数组必须已排序)
int index = Arrays.binarySearch(arr, 5); // 2
int index2 = Arrays.binarySearch(arr, 6); // -4(负数表示未找到)
// 线性查找(自己实现)
public static int linearSearch(int[] arr, int target) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] == target) {
return i;
}
}
return -1;
}4. 数组填充
java
int[] arr = new int[5];
// 填充整个数组
Arrays.fill(arr, 10); // [10, 10, 10, 10, 10]
// 填充部分
Arrays.fill(arr, 1, 4, 20); // [10, 20, 20, 20, 10]5. 数组比较
java
int[] arr1 = {1, 2, 3};
int[] arr2 = {1, 2, 3};
int[] arr3 = {1, 2, 4};
// == 比较引用
System.out.println(arr1 == arr2); // false
// Arrays.equals 比较内容
System.out.println(Arrays.equals(arr1, arr2)); // true
System.out.println(Arrays.equals(arr1, arr3)); // false📖 四、Arrays 工具类
java
import java.util.Arrays;
int[] arr = {5, 2, 8, 1, 9};
// 排序
Arrays.sort(arr);
// 转字符串
String str = Arrays.toString(arr); // "[1, 2, 5, 8, 9]"
// 二分查找
int index = Arrays.binarySearch(arr, 5);
// 填充
Arrays.fill(arr, 0);
// 复制
int[] copy = Arrays.copyOf(arr, arr.length);
// 复制范围
int[] copy2 = Arrays.copyOfRange(arr, 1, 4);
// 比较
boolean equal = Arrays.equals(arr, copy);
// 转 List
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);📖 五、常见应用
1. 数组反转
java
public static void reverse(int[] arr) {
int left = 0, right = arr.length - 1;
while (left < right) {
int temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
left++;
right--;
}
}2. 最大值和最小值
java
public static int max(int[] arr) {
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}
public static int min(int[] arr) {
int min = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] < min) {
min = arr[i];
}
}
return min;
}3. 数组求和与平均值
java
public static int sum(int[] arr) {
int sum = 0;
for (int num : arr) {
sum += num;
}
return sum;
}
public static double average(int[] arr) {
return (double) sum(arr) / arr.length;
}4. 冒泡排序
java
public static void bubbleSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}⚠️ 常见陷阱
陷阱1:数组越界
数组下标从 0 开始,最后一个元素下标是 length - 1。访问 arr[arr.length] 会抛出 ArrayIndexOutOfBoundsException。
陷阱2:混淆 length 和 length()
数组长度是属性 arr.length,字符串长度是方法 str.length()。
陷阱3:二维数组不一定是矩形
Java 二维数组本质是“数组的数组”,每一行长度可以不同。
陷阱4:数组拷贝只复制引用
对象数组复制后,数组是新的,但里面的对象引用仍指向同一批对象。
🆚 Java vs C 对比
| 特性 | C 数组 | Java 数组 |
|---|---|---|
| 越界检查 | 无,可能破坏内存 | 有,抛运行时异常 |
| 长度信息 | 通常需要额外传入 | 自带 length |
| 多维数组 | 连续内存或指针数组 | 数组的数组 |
| 初始化 | 未初始化可能是垃圾值 | 有默认值 |
对 C 程序员来说,Java 数组更安全,但也更受约束。它保留长度、检查越界,并且数组本身是对象。
💡 最佳实践
- 检查数组长度
java
if (arr != null && arr.length > 0) {
// 安全访问
}- 使用增强 for 循环
java
// ✅ 推荐
for (int num : arr) {
System.out.println(num);
}
// ❌ 不推荐(如果不需要索引)
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}- 使用 Arrays 工具类
java
// ✅ 推荐
Arrays.sort(arr);
Arrays.toString(arr);
// ❌ 不推荐:自己实现📝 练习
完成 练习/Ex04_Arrays.java:
- 数组基本操作
- 数组排序和查找
- 多维数组
- 数组算法实现
- Arrays 工具类使用
- 综合:成绩管理系统
🎓 下一步
- 第5课:方法 - 方法定义、参数传递、递归