|
|
@@ -0,0 +1,915 @@
|
|
|
+# JavaSE 基础 — Day04 笔记
|
|
|
+
|
|
|
+> **日期**:2026-07-16
|
|
|
+> **项目**:`c260716`
|
|
|
+> **作者**:WanJL
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 一、多维数组
|
|
|
+
|
|
|
+### 1. 多维数组概述
|
|
|
+
|
|
|
+Java 中的多维数组本质上是**数组的数组**:
|
|
|
+
|
|
|
+| 维度 | 本质 | 说明 |
|
|
|
+|------|------|------|
|
|
|
+| **一维数组** | 元素是数据类型的变量或常量 | `int[]` → 元素是 `int` |
|
|
|
+| **二维数组** | 元素是一维数组 | `int[][]` → 元素是 `int[]` |
|
|
|
+| **三维数组** | 元素是二维数组 | `int[][][]` → 元素是 `int[][]` |
|
|
|
+
|
|
|
+> **核心概念**:二维数组的每个元素其实是一维数组的**引用地址值**。
|
|
|
+
|
|
|
+#### 二维数组的定义格式
|
|
|
+
|
|
|
+```java
|
|
|
+数组类型[][] 数组名 = new 数组类型[二维数组长度][一维数组长度];
|
|
|
+// 示例:3行2列的二维数组
|
|
|
+int[][] arr = new int[3][2]; // [行数][列数]
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 2. 二维数组的遍历
|
|
|
+
|
|
|
+二维数组需要**两层循环嵌套**来遍历:
|
|
|
+
|
|
|
+```java
|
|
|
+// 外层循环控制行数(二维数组的长度)
|
|
|
+for (int i = 0; i < arr.length; i++) {
|
|
|
+ // 内层循环控制列数(每个一维数组的长度)
|
|
|
+ for (int j = 0; j < arr[i].length; j++) {
|
|
|
+ System.out.print(arr[i][j] + " ");
|
|
|
+ }
|
|
|
+ System.out.println();
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+- `arr.length` — 二维数组的长度(即行数)
|
|
|
+- `arr[i].length` — 第 i 行一维数组的长度(即列数)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 3. 二维数组的静态初始化
|
|
|
+
|
|
|
+```java
|
|
|
+int[][] arr1 = {
|
|
|
+ {1, 2, 3},
|
|
|
+ {4, 5, 6},
|
|
|
+ {7, 8, 9}
|
|
|
+};
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 4. 不规则的二维数组(每个一维数组长度不同)
|
|
|
+
|
|
|
+二维数组中的一维数组**不必长度相同**:
|
|
|
+
|
|
|
+```java
|
|
|
+int[] arr01 = {1, 3};
|
|
|
+int[] arr02 = {4, 5, 6};
|
|
|
+int[] arr03 = {7, 8, 9, 15};
|
|
|
+int[][] arr2 = {arr01, arr02, arr03}; // 存放的是一维数组的引用地址
|
|
|
+```
|
|
|
+
|
|
|
+遍历时同样使用两层循环,每个内层循环以对应一维数组的长度为界:
|
|
|
+
|
|
|
+```java
|
|
|
+for (int i = 0; i < arr2.length; i++) {
|
|
|
+ for (int j = 0; j < arr2[i].length; j++) {
|
|
|
+ System.out.print(arr2[i][j] + " ");
|
|
|
+ }
|
|
|
+ System.out.println();
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 二、增强 for 循环(foreach)
|
|
|
+
|
|
|
+### 1. foreach 概述
|
|
|
+
|
|
|
+**增强 for 循环(foreach)** 是 Java 提供的一种简化数组遍历的语法,作用和普通 `for` 循环一样,主要用于**遍历数组或集合中的所有元素**。
|
|
|
+
|
|
|
+#### 语法格式
|
|
|
+
|
|
|
+```java
|
|
|
+for (数据类型 变量 : 数组名) {
|
|
|
+ 代码块
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+#### 基本示例
|
|
|
+
|
|
|
+```java
|
|
|
+int[] arr = {1, 2, 3, 4, 5, 6, 8};
|
|
|
+for (int a : arr) {
|
|
|
+ System.out.print(a + " ");
|
|
|
+}
|
|
|
+// 输出:1 2 3 4 5 6 8
|
|
|
+```
|
|
|
+
|
|
|
+> ⚠️ **注意**:foreach 遍历数组时**无法获取索引值**,所以只适合**遍历全部元素**。如果需要操作某个指定索引位置的元素,仍需使用普通 `for` 循环。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 2. foreach 遍历二维数组
|
|
|
+
|
|
|
+```java
|
|
|
+int[] arr01 = {1, 3};
|
|
|
+int[] arr02 = {4, 5, 6};
|
|
|
+int[] arr03 = {7, 8, 9, 15};
|
|
|
+int[][] arr2 = {arr01, arr02, arr03};
|
|
|
+
|
|
|
+for (int[] a : arr2) { // 外层 foreach:遍历二维数组,得到每个一维数组
|
|
|
+ for (int a1 : a) { // 内层 foreach:遍历一维数组,得到每个元素
|
|
|
+ System.out.print(a1 + " ");
|
|
|
+ }
|
|
|
+ System.out.println();
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+> 外层 `int[] a` 表示二维数组中的每个元素是一维数组,内层 `int a1` 表示一维数组中的每个元素是 `int`。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 3. for 循环 vs foreach 对比
|
|
|
+
|
|
|
+| 特性 | 普通 for 循环 | 增强 for 循环(foreach) |
|
|
|
+|------|-------------|------------------------|
|
|
|
+| **语法** | `for(int i=0; i<len; i++)` | `for(int a : arr)` |
|
|
|
+| **索引访问** | 支持(通过 `i`) | 不支持 |
|
|
|
+| **适用场景** | 需要索引、修改元素、部分遍历 | 只需要遍历全部元素 |
|
|
|
+| **代码简洁性** | 较繁琐 | 更简洁 |
|
|
|
+| **可读性** | 一般 | 更好 |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 三、数组工具类 `java.util.Arrays`
|
|
|
+
|
|
|
+### 1. 概述
|
|
|
+
|
|
|
+`java.util.Arrays` 是 Java 提供的**数组工具类**,包含大量操作数组的静态方法。
|
|
|
+
|
|
|
+> **命名特点**:如果一个类的类名是**名词 + `s`**,大多数情况下这个类就是**工具类**。
|
|
|
+
|
|
|
+**使用前提**:需要导包
|
|
|
+
|
|
|
+```java
|
|
|
+import java.util.Arrays;
|
|
|
+// import 是导包的关键字,后面跟着【类全路径名】—— 包名.类名
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 2. 常用方法
|
|
|
+
|
|
|
+| 方法 | 作用 | 示例 |
|
|
|
+|------|------|------|
|
|
|
+| `Arrays.sort(arr)` | 对数组进行**升序排序** | `Arrays.sort(arr);` |
|
|
|
+| `Arrays.toString(arr)` | 将数组转换为**字符串**输出 | `System.out.println(Arrays.toString(arr));` |
|
|
|
+| `Arrays.copyOf(arr, newLength)` | **拷贝数组**(扩展或截断,多余补默认值) | `int[] copy = Arrays.copyOf(arr, 10);` |
|
|
|
+| `Arrays.copyOfRange(arr, from, to)` | 拷贝数组的**指定范围** `[from, to)` | `int[] range = Arrays.copyOfRange(arr, 1, 4);` |
|
|
|
+| `Arrays.binarySearch(arr, key)` | **二分查找**(数组必须先排序),返回索引值(未找到返回负数) | `int index = Arrays.binarySearch(arr, 689);` |
|
|
|
+
|
|
|
+#### 详细示例
|
|
|
+
|
|
|
+```java
|
|
|
+int[] arr = {7, 6, 78, 1, 689, 87, 165, 7, 4, 5, 8};
|
|
|
+
|
|
|
+// 排序
|
|
|
+Arrays.sort(arr);
|
|
|
+System.out.println(Arrays.toString(arr));
|
|
|
+// 输出:[1, 4, 5, 6, 7, 7, 8, 78, 87, 165, 689]
|
|
|
+
|
|
|
+// 拷贝(扩展长度,多余补 0)
|
|
|
+int[] copy = Arrays.copyOf(arr, 10);
|
|
|
+System.out.println(Arrays.toString(copy));
|
|
|
+
|
|
|
+// 拷贝指定范围 [1, 4) — 包含索引1,不包含索引4
|
|
|
+int[] range = Arrays.copyOfRange(arr, 1, 4);
|
|
|
+System.out.println(Arrays.toString(range)); // 输出:[4, 5, 6]
|
|
|
+
|
|
|
+// 二分查找(需先排序),返回元素在数组中的索引
|
|
|
+int index = Arrays.binarySearch(arr, 689);
|
|
|
+System.out.println(index); // 输出:10(排序后 689 在索引 10)
|
|
|
+```
|
|
|
+
|
|
|
+> ⚠️ `Arrays.binarySearch()` 要求数组**必须先排序**,否则结果不确定。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 四、课堂练习详解
|
|
|
+
|
|
|
+### 练习 01:首尾对称交换数组元素
|
|
|
+
|
|
|
+**题目**:定义数组 `{10, 20, 30, 40, 50}`,将第 1 个与第 5 个交换、第 2 个与第 4 个交换(首尾对称交换)。
|
|
|
+
|
|
|
+**核心思路**:使用**加减法交换**(不借助第三个变量)实现两个位置的元素互换。
|
|
|
+
|
|
|
+```java
|
|
|
+int[] arr = {10, 20, 30, 40, 50};
|
|
|
+
|
|
|
+// 首尾交换:第1位和第5位
|
|
|
+arr[0] = arr[0] + arr[4];
|
|
|
+arr[4] = arr[0] - arr[4];
|
|
|
+arr[0] = arr[0] - arr[4];
|
|
|
+
|
|
|
+// 首尾交换:第2位和第4位
|
|
|
+arr[1] = arr[1] + arr[3];
|
|
|
+arr[3] = arr[1] - arr[3];
|
|
|
+arr[1] = arr[1] - arr[3];
|
|
|
+```
|
|
|
+
|
|
|
+**变量交换的三种方式**:
|
|
|
+
|
|
|
+| 方式 | 代码 | 优点 | 缺点 |
|
|
|
+|------|------|------|------|
|
|
|
+| **借助临时变量** | `tmp = a; a = b; b = tmp;` | 直观、安全 | 多用一个变量 |
|
|
|
+| **加减法交换** | `a = a + b; b = a - b; a = a - b;` | 无需额外变量 | 可能溢出(大数) |
|
|
|
+| **异或交换** | `a = a ^ b; b = a ^ b; a = a ^ b;` | 无需额外变量 | 可读性差 |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 练习 02:数组循环右移
|
|
|
+
|
|
|
+**题目**:定义数组 `{1, 2, 3, 4, 5}`,将数组中的所有元素向右移动 2 个位置,超出数组范围的元素循环移到数组开头。
|
|
|
+
|
|
|
+**解题思路**:
|
|
|
+
|
|
|
+先理解**全体向右移动 1 位**的过程:
|
|
|
+1. 先把最后一个元素保存起来
|
|
|
+2. 倒数第 2 位 → 倒数第 1 位
|
|
|
+3. 倒数第 3 位 → 倒数第 2 位
|
|
|
+4. ...依此类推...
|
|
|
+5. 第 1 位(索引 0)→ 第 2 位(索引 1)
|
|
|
+6. 把保存起来的最后一个元素 → 第 1 位(索引 0)
|
|
|
+
|
|
|
+**执行步骤图解**(右移 1 位):
|
|
|
+```
|
|
|
+原始: [1, 2, 3, 4, 5]
|
|
|
+第1步:保存最后一个元素 last = 5
|
|
|
+第2步:从后往前移动 ←
|
|
|
+ [1, 2, 3, 4, 4] // arr[4]=arr[3]
|
|
|
+ [1, 2, 3, 3, 4] // arr[3]=arr[2]
|
|
|
+ [1, 2, 2, 3, 4] // arr[2]=arr[1]
|
|
|
+ [1, 1, 2, 3, 4] // arr[1]=arr[0]
|
|
|
+第3步:arr[0] = last
|
|
|
+结果: [5, 1, 2, 3, 4]
|
|
|
+```
|
|
|
+
|
|
|
+**代码实现**:
|
|
|
+
|
|
|
+```java
|
|
|
+int[] arr = {1, 2, 3, 4, 5};
|
|
|
+int k = 2; // 右移位数
|
|
|
+
|
|
|
+// 如果k大于数组长度,取模(移动6次 = 移动1次)
|
|
|
+k = k % arr.length;
|
|
|
+
|
|
|
+// 整体右移k位(循环右移)
|
|
|
+for (int i = 0; i < k; i++) {
|
|
|
+ // 保存最后一个元素
|
|
|
+ int last = arr[arr.length - 1];
|
|
|
+ // 从后往前,每个元素向后移动1位
|
|
|
+ for (int j = arr.length - 1; j > 0; j--) {
|
|
|
+ arr[j] = arr[j - 1];
|
|
|
+ }
|
|
|
+ // 把最后一个元素放到第0位
|
|
|
+ arr[0] = last;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+> **关键点**:
|
|
|
+> - 内层循环必须**从后往前**遍历(`j = length-1` → `j > 0`),否则前面的值会被覆盖
|
|
|
+> - `k = k % arr.length` 解决 k 大于数组长度时的重复移动问题(如移动 6 次 = 移动 1 次)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 练习 03:数组去重
|
|
|
+
|
|
|
+**题目**:定义数组 `{5, 2, 8, 2, 5, 9, 1, 8, 3}`,去除重复元素,只保留第一次出现的元素,输出去重后的新数组。
|
|
|
+
|
|
|
+**核心思路**:
|
|
|
+1. **第一步**:统计不重复元素的个数
|
|
|
+2. **第二步**:创建新数组(长度为统计结果)
|
|
|
+3. **第三步**:将不重复元素放入新数组
|
|
|
+
|
|
|
+**判断元素是否重复的方式**:检查当前元素 `arr[i]` 在它**之前**是否出现过(即 `arr[0]` ~ `arr[i-1]` 中是否有相同的值)。
|
|
|
+
|
|
|
+```java
|
|
|
+int[] arr = {5, 2, 8, 2, 5, 9, 1, 8, 3};
|
|
|
+int count = 0; // 不重复元素的个数
|
|
|
+
|
|
|
+// 第一步:统计不重复元素的个数
|
|
|
+for (int i = 0; i < arr.length; i++) {
|
|
|
+ boolean b = false; // 标记:先认为当前元素没有重复
|
|
|
+ for (int j = 0; j < i; j++) { // 检查 arr[i] 在它之前是否出现过
|
|
|
+ if (arr[i] == arr[j]) {
|
|
|
+ b = true; // 找到重复,标记改为 true
|
|
|
+ break; // 跳出内层循环
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (b == false) { // 没有重复,计数
|
|
|
+ count++;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 第二步:创建新数组
|
|
|
+int[] newArr = new int[count];
|
|
|
+int index = 0; // 新数组的索引
|
|
|
+
|
|
|
+// 第三步:将不重复元素放入新数组
|
|
|
+for (int i = 0; i < arr.length; i++) {
|
|
|
+ boolean b = false;
|
|
|
+ for (int j = 0; j < i; j++) {
|
|
|
+ if (arr[i] == arr[j]) {
|
|
|
+ b = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (b == false) { // 不重复的元素
|
|
|
+ newArr[index] = arr[i]; // 放入新数组
|
|
|
+ index++;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 输出新数组
|
|
|
+for (int i = 0; i < newArr.length; i++) {
|
|
|
+ System.out.print(newArr[i] + " ");
|
|
|
+}
|
|
|
+// 输出:5 2 8 9 1 3
|
|
|
+```
|
|
|
+
|
|
|
+> **核心技巧**:
|
|
|
+> - 使用**布尔标记 `boolean b`** 来判断元素是否重复
|
|
|
+> - 内层循环 `j < i` 只检查当前元素**之前**的元素,确保只保留第一次出现的元素
|
|
|
+> - 两步走:先统计个数 → 再填充数据(因为数组长度在创建后不可改变)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 五、课后作业讲解(7月15日作业)
|
|
|
+
|
|
|
+### 作业 07:数组元素求和
|
|
|
+
|
|
|
+**题目**:定义数组 `{11, 22, 33, 44, 55}`,用 `for` 循环遍历数组,计算所有元素的总和。
|
|
|
+
|
|
|
+**知识点**:数组遍历、累加求和
|
|
|
+
|
|
|
+```java
|
|
|
+int[] arr = {11, 22, 33, 44, 55};
|
|
|
+int sum = 0; // 记录累加和
|
|
|
+for (int i = 0; i < arr.length; i++) {
|
|
|
+ sum += arr[i]; // 通过 arr[i] 获取每个元素,累加到 sum
|
|
|
+}
|
|
|
+System.out.println(sum); // 输出:165
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 作业 08:找数组最大值
|
|
|
+
|
|
|
+**题目**:定义数组 `{3, 8, 1, 9, 4, 7, 2}`,找出数组中的最大值。
|
|
|
+
|
|
|
+**知识点**:数组遍历、打擂法(假设法)
|
|
|
+
|
|
|
+```java
|
|
|
+int[] arr = {3, 8, 1, 9, 4, 7, 2};
|
|
|
+int max = arr[0]; // 先假设第一个元素是最大值
|
|
|
+for (int i = 1; i < arr.length; i++) {
|
|
|
+ if (arr[i] > max) { // 如果有元素比当前最大值还大
|
|
|
+ max = arr[i]; // 更新最大值
|
|
|
+ }
|
|
|
+}
|
|
|
+System.out.println(max); // 输出:9
|
|
|
+```
|
|
|
+
|
|
|
+> **打擂法核心思路**:先假设第一个元素是最大值,然后遍历数组,遇到更大的就更新。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 作业 09:数组倒序输出
|
|
|
+
|
|
|
+**题目**:定义数组 `{1, 2, 3, 4, 5}`,从后往前遍历,将元素倒序输出。
|
|
|
+
|
|
|
+**知识点**:for 循环逆序遍历
|
|
|
+
|
|
|
+```java
|
|
|
+int[] arr = {1, 2, 3, 4, 5};
|
|
|
+// 从最大索引开始,递减到 0
|
|
|
+for (int i = arr.length - 1; i >= 0; i--) {
|
|
|
+ System.out.println(arr[i]);
|
|
|
+}
|
|
|
+// 输出:
|
|
|
+// 5
|
|
|
+// 4
|
|
|
+// 3
|
|
|
+// 2
|
|
|
+// 1
|
|
|
+```
|
|
|
+
|
|
|
+> 从 `arr.length - 1`(最后一个元素的索引)开始,到 `0`(第一个元素的索引)结束,每次递减 1。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 作业 10:统计奇偶数个数
|
|
|
+
|
|
|
+**题目**:定义数组 `{12, 7, 9, 24, 15, 8, 31, 46}`,遍历数组,统计奇数和偶数的个数。
|
|
|
+
|
|
|
+**知识点**:数组遍历、取模判断、统计计数
|
|
|
+
|
|
|
+```java
|
|
|
+int[] arr = {12, 7, 9, 24, 15, 8, 31, 46};
|
|
|
+int count = 0; // 奇数个数
|
|
|
+for (int i = 0; i < arr.length; i++) {
|
|
|
+ if (arr[i] % 2 != 0) { // 余2不等于0,说明是奇数
|
|
|
+ count++;
|
|
|
+ }
|
|
|
+}
|
|
|
+System.out.println("奇数个数:" + count + ",偶数个数:" + (arr.length - count));
|
|
|
+// 输出:奇数个数:4,偶数个数:4
|
|
|
+```
|
|
|
+
|
|
|
+> **偶数的判定**:`arr[i] % 2 == 0`
|
|
|
+> **奇数的判定**:`arr[i] % 2 != 0`
|
|
|
+> 偶数个数 = 数组总长度 - 奇数个数
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 六、随堂练习要点
|
|
|
+
|
|
|
+1. **多维数组本质**:数组的数组,二维数组的元素是一维数组的引用地址
|
|
|
+2. **二维数组定义**:`int[][] arr = new int[3][2];`(3 行 2 列)
|
|
|
+3. **二维数组遍历**:两层循环嵌套,外层行数 `arr.length`,内层列数 `arr[i].length`
|
|
|
+4. **不规则二维数组**:每个一维数组长度可以不同
|
|
|
+5. **foreach 语法**:`for(数据类型 变量 : 数组名) { }`,适合遍历全部元素
|
|
|
+6. **foreach 局限性**:无法获取索引值,无法修改元素,只能读取
|
|
|
+7. **Arrays 工具类**:`java.util.Arrays`,操作数组的静态方法集合
|
|
|
+8. **`Arrays.sort(arr)`**:对数组进行升序排序
|
|
|
+9. **`Arrays.toString(arr)`**:将数组转换为字符串输出
|
|
|
+10. **`Arrays.copyOf(arr, n)`**:拷贝数组,指定新长度,多余补默认值
|
|
|
+11. **`Arrays.copyOfRange(arr, from, to)`**:拷贝指定范围 [from, to)
|
|
|
+12. **`Arrays.binarySearch(arr, key)`**:二分查找(必须先排序)
|
|
|
+13. **变量交换-临时变量法**:`tmp = a; a = b; b = tmp;`
|
|
|
+14. **变量交换-加减法**:`a = a + b; b = a - b; a = a - b;`
|
|
|
+15. **首尾交换**:利用对称性,第 i 位与第 length-1-i 位交换
|
|
|
+16. **循环右移**:从后往前逐个移动,保存最后一个元素放到开头
|
|
|
+17. **取模优化**:`k = k % arr.length` 解决 k 大于数组长度的问题
|
|
|
+18. **数组去重思路**:统计不重复个数 → 创建新数组 → 填充不重复元素
|
|
|
+19. **布尔标记法**:使用 `boolean` 变量标记元素是否重复
|
|
|
+20. **打擂法找最大值**:假设第一个是最大值,遇到更大的就更新
|
|
|
+21. **数组求和**:遍历数组,累加每个元素
|
|
|
+22. **倒序输出**:从 `length-1` 到 `0` 递减遍历
|
|
|
+23. **奇偶判断**:`n % 2 == 0` 偶,`n % 2 != 0` 奇
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 七、知识拓展
|
|
|
+
|
|
|
+### 1. 数组的地址值
|
|
|
+
|
|
|
+当直接打印数组变量时,输出的是数组在堆内存中的**地址值**:
|
|
|
+
|
|
|
+```java
|
|
|
+int[] a = new int[10];
|
|
|
+System.out.println(a); // 输出类似:[I@b4c966a
|
|
|
+```
|
|
|
+
|
|
|
+地址值含义:
|
|
|
+- `[` — 一维数组
|
|
|
+- `I` — 元素类型为 int
|
|
|
+- `@` — 分隔符
|
|
|
+- `b4c966a` — 堆内存中的十六进制地址
|
|
|
+
|
|
|
+### 2. 二维数组的内存结构
|
|
|
+
|
|
|
+```
|
|
|
+二维数组 arr2 = {arr01, arr02, arr03} 在内存中:
|
|
|
+┌──────────┐
|
|
|
+│ arr2[0] │────→ arr01: [1, 3]
|
|
|
+├──────────┤
|
|
|
+│ arr2[1] │────→ arr02: [4, 5, 6]
|
|
|
+├──────────┤
|
|
|
+│ arr2[2] │────→ arr03: [7, 8, 9, 15]
|
|
|
+└──────────┘
|
|
|
+```
|
|
|
+
|
|
|
+二维数组的每个元素存储的是**一维数组的引用地址**,而不是元素本身。
|
|
|
+
|
|
|
+### 3. 二分查找原理
|
|
|
+
|
|
|
+`Arrays.binarySearch()` 基于**二分查找算法**(Binary Search):
|
|
|
+
|
|
|
+- **前提**:数组必须已排序
|
|
|
+- **原理**:每次将查找范围缩小一半,与中间元素比较
|
|
|
+- **时间复杂度**:O(log n) — 效率远高于线性查找 O(n)
|
|
|
+
|
|
|
+```
|
|
|
+已排序数组:[1, 4, 5, 6, 7, 7, 8, 78, 87, 165, 689]
|
|
|
+查找目标:689
|
|
|
+
|
|
|
+第1次:比较中间元素 7 → 689 > 7,在右半部分查找
|
|
|
+第2次:比较中间元素 87 → 689 > 87,继续在右半部分查找
|
|
|
+第3次:比较中间元素 165 → 689 > 165,继续在右半部分查找
|
|
|
+第4次:找到 689,返回索引 10
|
|
|
+```
|
|
|
+
|
|
|
+### 4. 数组拷贝的深浅问题
|
|
|
+
|
|
|
+`Arrays.copyOf()` 和 `Arrays.copyOfRange()` 执行的是**浅拷贝**:
|
|
|
+
|
|
|
+- 对于基本数据类型:拷贝的是值,互不影响 ✓
|
|
|
+- 对于引用数据类型:拷贝的是引用地址,新数组和原数组指向同一个对象 ⚠️
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 八、完整代码汇总
|
|
|
+
|
|
|
+### Demo01.java — 多维数组
|
|
|
+
|
|
|
+```java
|
|
|
+/**
|
|
|
+ * @author WanJl
|
|
|
+ * @version 1.0
|
|
|
+ * @title Demo01
|
|
|
+ * @description 多维数组
|
|
|
+ * @create 2026/7/16
|
|
|
+ */
|
|
|
+public class Demo01 {
|
|
|
+ public static void main(String[] args) {
|
|
|
+ /*
|
|
|
+ 一维数组中所有的元素都是数据类型的变量或常量
|
|
|
+ 二维数组中所有的元素都是一维数组
|
|
|
+ 三维数组中所有的元素都是二维数组
|
|
|
+ ......
|
|
|
+
|
|
|
+ Java多维数组的本质:其实就是数组的数组,二维数组的元素其实就是一维数组的引用地址值
|
|
|
+
|
|
|
+ 二维数组的定义的格式:
|
|
|
+ 数组类型[][] 数组名=new 数组类型[二维数组长度][一维数组长度];
|
|
|
+ */
|
|
|
+ //数组类型[][] 数组名=new 数组类型[二维数组长度][一维数组长度];
|
|
|
+ int[][] arr = new int[3][2]; //[行数][列数]
|
|
|
+
|
|
|
+ //遍历二维数组需要两层循环嵌套
|
|
|
+ for (int i = 0; i < arr.length; i++) {
|
|
|
+ for (int j = 0; j < arr[i].length; j++) {
|
|
|
+ System.out.print(arr[i][j] + " ");
|
|
|
+ }
|
|
|
+ System.out.println();
|
|
|
+ }
|
|
|
+ // 静态初始化二维数组----三行三列
|
|
|
+ int[][] arr1 = {
|
|
|
+ {1, 2, 3},
|
|
|
+ {4, 5, 6},
|
|
|
+ {7, 8, 9}
|
|
|
+ };
|
|
|
+ for (int i = 0; i < arr1.length; i++) {
|
|
|
+ for (int j = 0; j < arr1[i].length; j++) {
|
|
|
+ System.out.print(arr1[i][j] + " ");
|
|
|
+ }
|
|
|
+ System.out.println();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 二维数组中的一维数组,不是必须要相同长度的,长度是不一样的。
|
|
|
+ int[] arr01 = {1, 3};
|
|
|
+ int[] arr02 = {4, 5, 6};
|
|
|
+ int[] arr03 = {7, 8, 9, 15};
|
|
|
+ int[][] arr2 = {arr01, arr02, arr03}; //二维数组存放的其实就是一维数组的引用地址
|
|
|
+ for (int i = 0; i < arr2.length; i++) {
|
|
|
+ for (int j = 0; j < arr2[i].length; j++) {
|
|
|
+ System.out.print(arr2[i][j] + " ");
|
|
|
+ }
|
|
|
+ System.out.println();
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### Demo02.java — foreach 增强 for 循环
|
|
|
+
|
|
|
+```java
|
|
|
+/**
|
|
|
+ * @author WanJl
|
|
|
+ * @version 1.0
|
|
|
+ * @title Demo02
|
|
|
+ * @description foreach迭代-增强for循环
|
|
|
+ * @create 2026/7/16
|
|
|
+ */
|
|
|
+public class Demo02 {
|
|
|
+ public static void main(String[] args) {
|
|
|
+ //我们之前使用的for循环,是for(int i=0;i<10;i++)
|
|
|
+ //可以使用增强for循环--foreach,作用和for循环一样
|
|
|
+ //主要是用来进行数组遍历
|
|
|
+ /*
|
|
|
+ 格式:
|
|
|
+ for(数据类型 变量 : 数组名){
|
|
|
+ 代码块
|
|
|
+ }
|
|
|
+ */
|
|
|
+ int[] arr = {1, 2, 3, 4, 5, 6, 8};
|
|
|
+ for (int a : arr) {
|
|
|
+ System.out.print(a + " ");
|
|
|
+ }
|
|
|
+ System.out.println();
|
|
|
+ /*
|
|
|
+ foreach 遍历的数组,无法获取索引值,所以只适合遍历全部元素。想要获取某个索引位置的元素,需要for循环
|
|
|
+ */
|
|
|
+
|
|
|
+ int[] arr01 = {1, 3};
|
|
|
+ int[] arr02 = {4, 5, 6};
|
|
|
+ int[] arr03 = {7, 8, 9, 15};
|
|
|
+ int[][] arr2 = {arr01, arr02, arr03};
|
|
|
+ for (int[] a : arr2) { //外层foreach
|
|
|
+ for (int a1 : a) { //内层foreach
|
|
|
+ System.out.print(a1 + " ");
|
|
|
+ }
|
|
|
+ System.out.println();
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### Demo03.java — Arrays 数组工具类
|
|
|
+
|
|
|
+```java
|
|
|
+import java.util.Arrays;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @author WanJl
|
|
|
+ * @version 1.0
|
|
|
+ * @title Demo03
|
|
|
+ * @description 数组工具类 : java.util.Arrays;
|
|
|
+ * @create 2026/7/16
|
|
|
+ */
|
|
|
+public class Demo03 {
|
|
|
+ public static void main(String[] args) {
|
|
|
+ /*
|
|
|
+ 数组工具类 : java.util.Arrays;
|
|
|
+ java中的命名特点,如果一个类的类名 是名词+s,那么大多数情况下,这个类就是一个工具类
|
|
|
+ */
|
|
|
+ int[] arr = {7, 6, 78, 1, 689, 87, 165, 7, 4, 5, 8};
|
|
|
+ //使用工具类对数组进行排序
|
|
|
+ Arrays.sort(arr);
|
|
|
+
|
|
|
+ //输出arr数组--Arrays.toString方法 是直接把arr数组转换成字符串
|
|
|
+ System.out.println(Arrays.toString(arr));
|
|
|
+ // 拷贝(扩展长度,多余补 0)-- 把一个数组的元素复制到一个新的数组并指定新数组的长度,多余补 0
|
|
|
+ int[] copy = Arrays.copyOf(arr, 10);
|
|
|
+ System.out.println(Arrays.toString(copy));
|
|
|
+ // 拷贝指定范围 [1,4)
|
|
|
+ int[] range = Arrays.copyOfRange(arr, 1, 4);
|
|
|
+ System.out.println(Arrays.toString(range));
|
|
|
+ // 二分查找(需先排序),返回索引值
|
|
|
+ int index = Arrays.binarySearch(arr, 689);
|
|
|
+ System.out.println(index);
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### Exercises01.java — 首尾对称交换
|
|
|
+
|
|
|
+```java
|
|
|
+/**
|
|
|
+ * @author WanJl
|
|
|
+ * @version 1.0
|
|
|
+ * @title Exercises01
|
|
|
+ * @description 课堂练习01:首尾对称交换数组元素
|
|
|
+ * @create 2026/7/16
|
|
|
+ */
|
|
|
+public class Exercises01 {
|
|
|
+ public static void main(String[] args) {
|
|
|
+ int[] arr = {10, 20, 30, 40, 50};
|
|
|
+ System.out.print("交换前:");
|
|
|
+ for (int i = 0; i < arr.length; i++) {
|
|
|
+ System.out.print(arr[i] + " ");
|
|
|
+ }
|
|
|
+ System.out.println();
|
|
|
+ System.out.print("交换后:");
|
|
|
+ //首尾交换 第1位和第5位,第2位和第4位
|
|
|
+ arr[0] = arr[0] + arr[4];
|
|
|
+ arr[4] = arr[0] - arr[4];
|
|
|
+ arr[0] = arr[0] - arr[4];
|
|
|
+
|
|
|
+ arr[1] = arr[1] + arr[3];
|
|
|
+ arr[3] = arr[1] - arr[3];
|
|
|
+ arr[1] = arr[1] - arr[3];
|
|
|
+
|
|
|
+ for (int i = 0; i < arr.length; i++) {
|
|
|
+ System.out.print(arr[i] + " ");
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### Exercises02.java — 数组循环右移
|
|
|
+
|
|
|
+```java
|
|
|
+/**
|
|
|
+ * @author WanJl
|
|
|
+ * @version 1.0
|
|
|
+ * @title Exercises02
|
|
|
+ * @description 课堂练习02:数组循环右移
|
|
|
+ * @create 2026/7/16
|
|
|
+ */
|
|
|
+public class Exercises02 {
|
|
|
+ public static void main(String[] args) {
|
|
|
+ int[] arr = {1, 2, 3, 4, 5};
|
|
|
+ int k = 2; //右移位数
|
|
|
+ //如果k大于数组长度,要取模
|
|
|
+ k = k % arr.length;
|
|
|
+
|
|
|
+ System.out.print("移动前:");
|
|
|
+ for (int i = 0; i < arr.length; i++) {
|
|
|
+ System.out.print(arr[i] + " ");
|
|
|
+ }
|
|
|
+ System.out.println();
|
|
|
+ //整体右移k位(循环右移)
|
|
|
+ for (int i = 0; i < k; i++) {
|
|
|
+ //保存最后一个元素
|
|
|
+ int last = arr[arr.length - 1];
|
|
|
+ //从后往前,每个元素向后移动1位
|
|
|
+ for (int j = arr.length - 1; j > 0; j--) {
|
|
|
+ arr[j] = arr[j - 1];
|
|
|
+ }
|
|
|
+ //把最后1位给第0位
|
|
|
+ arr[0] = last;
|
|
|
+ }
|
|
|
+ System.out.print("移动后:");
|
|
|
+ for (int i = 0; i < arr.length; i++) {
|
|
|
+ System.out.print(arr[i] + " ");
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### Exercises03.java — 数组去重
|
|
|
+
|
|
|
+```java
|
|
|
+/**
|
|
|
+ * @author WanJl
|
|
|
+ * @version 1.0
|
|
|
+ * @title Exercises03
|
|
|
+ * @description 课堂练习03:数组去重
|
|
|
+ * @create 2026/7/16
|
|
|
+ */
|
|
|
+public class Exercises03 {
|
|
|
+ public static void main(String[] args) {
|
|
|
+ /*
|
|
|
+ 先统计不重复元素的个数
|
|
|
+ */
|
|
|
+ int[] arr = {5, 2, 8, 2, 5, 9, 1, 8, 3};
|
|
|
+ int count = 0; //个数
|
|
|
+ for (int i = 0; i < arr.length; i++) {
|
|
|
+ boolean b = false; //设置false,表示先认为当前的数组元素是没有重复的
|
|
|
+ for (int j = 0; j < i; j++) { //找 arr[i]元素,在arr数组中,有没有重复的元素。
|
|
|
+ if (arr[i] == arr[j]) { //只要找到一个重复的
|
|
|
+ b = true; //就把b设置为 true
|
|
|
+ break; //跳出内层循环
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (b == false) { //那就说明这个元素是没有重复的,就计数
|
|
|
+ count++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //创建的新的数组长度就是 count
|
|
|
+ int[] newArr = new int[count]; //动态初始化
|
|
|
+ int index = 0; //作为新数组的索引值
|
|
|
+ for (int i = 0; i < arr.length; i++) {
|
|
|
+ boolean b = false; //设置false,表示先认为当前的数组元素是没有重复的
|
|
|
+ //检查arr[i]在它之前是否有出现过
|
|
|
+ for (int j = 0; j < i; j++) {
|
|
|
+ if (arr[i] == arr[j]) {
|
|
|
+ b = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //判断如果我们设置的标记还是false,说明没有重复
|
|
|
+ if (b == false) {
|
|
|
+ newArr[index] = arr[i];
|
|
|
+ index++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for (int i = 0; i < newArr.length; i++) {
|
|
|
+ System.out.print(newArr[i] + " ");
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### HomeWork07.java — 数组求和
|
|
|
+
|
|
|
+```java
|
|
|
+/**
|
|
|
+ * @author WanJl
|
|
|
+ * @version 1.0
|
|
|
+ * @title HomeWork07
|
|
|
+ * @description 7月15日作业:数组元素求和
|
|
|
+ * @create 2026/7/16
|
|
|
+ */
|
|
|
+public class HomeWork07 {
|
|
|
+ public static void main(String[] args) {
|
|
|
+ int[] arr = {11, 22, 33, 44, 55};
|
|
|
+ int sum = 0;
|
|
|
+ for (int i = 0; i < arr.length; i++) {
|
|
|
+ sum += arr[i];
|
|
|
+ }
|
|
|
+ System.out.println(sum);
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### HomeWork08.java — 找数组最大值
|
|
|
+
|
|
|
+```java
|
|
|
+/**
|
|
|
+ * @author WanJl
|
|
|
+ * @version 1.0
|
|
|
+ * @title HomeWork08
|
|
|
+ * @description 7月15日作业:找数组最大值
|
|
|
+ * @create 2026/7/16
|
|
|
+ */
|
|
|
+public class HomeWork08 {
|
|
|
+ public static void main(String[] args) {
|
|
|
+ int[] arr = {3, 8, 1, 9, 4, 7, 2};
|
|
|
+ int max = arr[0]; //假设第一个元素是最大值
|
|
|
+ for (int i = 1; i < arr.length; i++) {
|
|
|
+ if (arr[i] > max) {
|
|
|
+ max = arr[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ System.out.println(max);
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### HomeWork09.java — 数组倒序输出
|
|
|
+
|
|
|
+```java
|
|
|
+/**
|
|
|
+ * @author WanJl
|
|
|
+ * @version 1.0
|
|
|
+ * @title HomeWork09
|
|
|
+ * @description 7月15日作业:数组倒序输出
|
|
|
+ * @create 2026/7/16
|
|
|
+ */
|
|
|
+public class HomeWork09 {
|
|
|
+ public static void main(String[] args) {
|
|
|
+ int[] arr = {1, 2, 3, 4, 5};
|
|
|
+ for (int i = arr.length - 1; i >= 0; i--) {
|
|
|
+ System.out.println(arr[i]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### HomeWork10.java — 统计奇偶数个数
|
|
|
+
|
|
|
+```java
|
|
|
+/**
|
|
|
+ * @author WanJl
|
|
|
+ * @version 1.0
|
|
|
+ * @title HomeWork10
|
|
|
+ * @description 7月15日作业:统计奇偶数个数
|
|
|
+ * @create 2026/7/16
|
|
|
+ */
|
|
|
+public class HomeWork10 {
|
|
|
+ public static void main(String[] args) {
|
|
|
+ int[] arr = {12, 7, 9, 24, 15, 8, 31, 46};
|
|
|
+ int count = 0; //奇数个数
|
|
|
+ for (int i = 0; i < arr.length; i++) {
|
|
|
+ if (arr[i] % 2 != 0) {
|
|
|
+ count++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ System.out.println("奇数个数:" + count + ",偶数个数:" + (arr.length - count));
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 九、拓展阅读
|
|
|
+
|
|
|
+| 概念 | 说明 |
|
|
|
+|------|------|
|
|
|
+| **多维数组** | Java 中多维数组是数组的数组,二维数组的元素是一维数组的引用地址 |
|
|
|
+| **二维数组遍历** | 外层循环遍历行(`arr.length`),内层循环遍历列(`arr[i].length`) |
|
|
|
+| **不规则数组** | 二维数组中的每个一维数组长度可以不同 |
|
|
|
+| **增强 for 循环** | `for(类型 变量 : 数组)` 语法,简化数组/集合遍历,无法获取索引 |
|
|
|
+| **Arrays 工具类** | `java.util.Arrays` 包含 sort、toString、copyOf、binarySearch 等静态方法 |
|
|
|
+| **Arrays.sort()** | 对数组进行快速排序(Dual-Pivot Quicksort) |
|
|
|
+| **Arrays.toString()** | 将数组转换为可读的字符串格式 `[elem1, elem2, ...]` |
|
|
|
+| **Arrays.copyOf()** | 数组拷贝,可指定新长度,扩展部分补默认值,截断部分丢弃 |
|
|
|
+| **Arrays.copyOfRange()** | 拷贝数组指定范围 `[from, to)`,包含 from 不包含 to |
|
|
|
+| **Arrays.binarySearch()** | 二分查找,数组必须先排序,返回索引值(未找到返回负数) |
|
|
|
+| **变量交换-临时变量** | `tmp = a; a = b; b = tmp;` 最直观的交换方式 |
|
|
|
+| **变量交换-加减法** | `a = a + b; b = a - b; a = a - b;` 不借助第三个变量 |
|
|
|
+| **数组循环右移** | 从后往前逐位移动,保存最后一位到第一位,外层套循环控制移动次数 |
|
|
|
+| **数组去重** | 两层循环 + 布尔标记,检查当前元素在它之前是否出现过 |
|
|
|
+| **打擂法** | 先假设第一个是最大值/最小值,遍历数组遇到更值就更新 |
|
|
|
+| **数组求和** | `sum += arr[i]` 遍历累加 |
|
|
|
+| **倒序遍历** | `for (int i = length-1; i >= 0; i--)` |
|
|
|
+| **奇偶判断** | `n % 2 == 0` 为偶数,`n % 2 != 0` 为奇数 |
|
|
|
+| **取模优化** | 对循环移动的位数取模,避免无效重复移动 |
|