主题
Java数组算法、工具类与方法完全指南
目录
一、核心知识点
1. 数组常见算法
1.1 数组翻转
概念:数组中对称位置上的元素互换
实现原理:
- 使用双指针法,一个指针从数组头部开始,一个从尾部开始
- 交换两个指针指向的元素,然后向中间移动
- 直到两个指针相遇

代码实现:
java
public class ArrayReverse {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
for (int min = 0, max = arr.length - 1; min < max; min++, max--) {
int temp = arr[min];
arr[min] = arr[max];
arr[max] = temp;
}
for (int i : arr) {
System.out.print(i + " ");
}
}
}1.2 冒泡排序 ⭐⭐⭐
概念:相邻两个元素比较大小,大的往后走,小的往前走(升序)
算法原理:
- 外层循环控制比较轮数(n-1轮)
- 内层循环控制每轮比较次数(每轮减少一次)
- 每次比较相邻元素,如果前者大于后者则交换
时间复杂度:O(n²)
空间复杂度:O(1)

代码实现:
java
public class BubbleSort {
public static void main(String[] args) {
int[] arr = {5, 4, 3, 2, 1};
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;
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}注意事项:
- 内层循环条件:
j < arr.length - 1 - i,避免索引越界 - 外层循环次数:
arr.length - 1次
1.3 二分查找 ⭐⭐⭐
概念:每次都计算数组的中间索引,然后和中间索引做比较,每次干掉一半
前提条件:数组元素必须是有序的(默认升序)
算法原理:
- 定义三个指针:min(最小索引)、max(最大索引)、mid(中间索引)
- 计算中间索引:
mid = (min + max) / 2 - 比较中间元素与目标值:
- 如果目标值大于中间元素,min = mid + 1
- 如果目标值小于中间元素,max = mid - 1
- 如果相等,找到目标
时间复杂度:O(log n)
空间复杂度:O(1)

代码实现:
java
public class BinarySearch {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int min = 0;
int max = arr.length - 1;
int mid = 0;
int key = 10;
while (min <= max) {
mid = (min + max) / 2;
if (key > arr[mid]) {
min = mid + 1;
} else if (key < arr[mid]) {
max = mid - 1;
} else {
System.out.println("找到了,索引是:" + mid);
break;
}
}
}
}2. 数组工具类
2.1 System类
概述:系统相关类,提供系统级操作方法
常用方法:
| 方法 | 说明 |
|---|---|
static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) | 数组复制 |
参数说明:
src:源数组,复制哪个数组中的元素srcPos:从源数组的哪个索引开始复制dest:目标数组,将元素复制到哪个数组中去destPos:从目标数组的哪个索引开始粘贴length:复制多少个元素
代码示例:
java
public class SystemDemo {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8};
int[] arr2 = new int[10];
System.arraycopy(arr, 0, arr2, 0, arr.length);
for (int element : arr2) {
System.out.print(element + " ");
}
}
}2.2 Arrays类 ⭐⭐⭐
概述:Java提供的数组工具类,包含大量数组操作方法
常用方法:
| 方法 | 说明 |
|---|---|
String toString(数组) | 按照[元素1, 元素2...]格式打印 |
void sort(数组) | 数组升序排序 |
int binarySearch(数组, 要查找的元素) | 二分查找,返回元素对应的索引 |
int[] copyOf(数组, 新数组长度) | 数组扩容,返回新数组 |
代码示例:
java
import java.util.Arrays;
public class ArraysDemo {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8};
// toString方法
System.out.println(Arrays.toString(arr));
// sort方法
int[] arr2 = {5, 4, 3, 2, 1};
Arrays.sort(arr2);
System.out.println(Arrays.toString(arr2));
// binarySearch方法
int index = Arrays.binarySearch(arr, 3);
System.out.println("索引:" + index);
// copyOf方法
int[] newArr = Arrays.copyOf(arr2, 10);
System.out.println(Arrays.toString(newArr));
}
}2.3 Hutool工具
概述:第三方工具库,提供更丰富的工具方法
使用步骤:
- 下载jar包
- 在模块下创建lib目录
- 将jar包复制到lib目录
- 右键lib目录 → Add as Library → 选择Module级别

ArrayUtil常用方法:
| 方法 | 说明 |
|---|---|
int max(数组) | 返回数组最大值 |
int indexOf(数组, 要查找的数据) | 顺序查找,指定的数据在数组中的位置 |
reverse(数组) | 数组翻转 |
代码示例:
java
import cn.hutool.core.util.ArrayUtil;
public class HutoolDemo {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8};
// 获取最大值
System.out.println("最大值:" + ArrayUtil.max(arr));
// 查找元素位置
System.out.println("索引:" + ArrayUtil.indexOf(arr, 3));
// 数组翻转
ArrayUtil.reverse(arr);
System.out.println(ArrayUtil.toString(arr));
}
}3. 二维数组
3.1 二维数组的定义
概念:数组中嵌套多个一维数组
定义格式:
动态初始化:
java
数据类型[][] 数组名 = new 数据类型[m][n];
数据类型 数组名[][] = new 数据类型[m][n];
数据类型[] 数组名[] = new 数据类型[m][n];m:二维数组长度(一维数组的个数)n:每个一维数组的长度
静态初始化:
java
数据类型[][] 数组名 = new 数据类型[][]{{元素1, 元素2...}, {元素1, 元素2...}, ...};简化静态初始化:
java
数据类型[][] 数组名 = {{元素1, 元素2...}, {元素1, 元素2...}, ...};代码示例:
java
public class TwoArrayDemo {
public static void main(String[] args) {
// 动态初始化
int[][] arr1 = new int[3][3];
// 动态初始化(不指定一维数组长度)
int[][] arr2 = new int[3][];
// 静态初始化
int[][] arr3 = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
// 不规则二维数组
String[][] arr4 = {{"唐僧", "孙悟空", "猪八戒"}, {"刘备", "关羽"}, {"金莲", "涛哥"}};
}
}
3.2 获取二维数组长度
格式:
- 二维数组长度:
数组名.length - 一维数组长度:
数组名[i].length
代码示例:
java
public class TwoArrayLength {
public static void main(String[] args) {
int[][] arr1 = new int[3][3];
// 获取二维数组长度
System.out.println("二维数组长度:" + arr1.length);
// 获取每个一维数组长度
for (int i = 0; i < arr1.length; i++) {
System.out.println("第" + i + "个一维数组长度:" + arr1[i].length);
}
}
}3.3 获取二维数组中的元素
格式:数组名[i][j]
i:一维数组在二维数组中的索引位置j:元素在一维数组中的索引位置
代码示例:
java
public class TwoArrayElement {
public static void main(String[] args) {
String[][] arr1 = {{"唐僧", "孙悟空", "猪八戒"}, {"刘备", "关羽"}, {"金莲", "涛哥"}};
System.out.println(arr1[0][0]); // 唐僧
System.out.println(arr1[1][1]); // 关羽
System.out.println(arr1[2][1]); // 涛哥
}
}
3.4 二维数组中存储元素
格式:数组名[i][j] = 值
代码示例:
java
public class TwoArrayStore {
public static void main(String[] args) {
int[][] arr1 = new int[3][3];
arr1[0][0] = 100;
arr1[0][1] = 200;
arr1[0][2] = 300;
arr1[1][0] = 1000;
arr1[1][1] = 2000;
arr1[1][2] = 3000;
arr1[2][0] = 10000;
arr1[2][1] = 20000;
arr1[2][2] = 30000;
// 遍历输出
for (int i = 0; i < arr1.length; i++) {
for (int j = 0; j < arr1[i].length; j++) {
System.out.println(arr1[i][j]);
}
}
}
}3.5 二维数组的遍历
方法:嵌套循环
- 外层循环遍历二维数组,获取每个一维数组
- 内层循环遍历每个一维数组
代码示例:
java
public class TwoArrayTraversal {
public static void main(String[] args) {
int[][] arr = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
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();
}
}
}4. 方法的使用
4.1 方法概述
为什么需要方法:
- 不能将所有功能的代码都放到一个main方法中,不利于维护
- 一个功能对应一个方法,便于模块化管理
方法的概念:拥有功能性代码的代码块
方法的通用定义格式:
java
修饰符 返回值类型 方法名(参数) {
方法体
return 结果;
}方法的四种类型:
- 无参无返回值方法
- 有参无返回值方法
- 无参有返回值方法
- 有参有返回值方法

4.2 无参无返回值方法
定义格式:
java
public static void 方法名() {
方法体
}注意事项:
void代表无返回值- 写了
void就不要写return 结果
调用方式:直接调用
java
方法名();代码示例:
java
public class MethodDemo01 {
public static void main(String[] args) {
add();
}
public static void add() {
int a = 10;
int b = 20;
int sum = a + b;
System.out.println("和:" + sum);
}
}
方法注意事项:
- 方法不调用不执行(main方法是JVM调用的)
- 方法不能互相嵌套
- 方法的执行顺序只和调用顺序有关

4.3 方法定义各部分解释
| 部分 | 说明 |
|---|---|
| 修饰符 | 固定为 public static |
| 返回值类型 | return 结果 中"结果"的数据类型 |
| 方法名 | 小驼峰命名,见名知意 |
| 参数 | 进入方法内部的数据,格式:数据类型 变量名 |
| 方法体 | 实现方法功能的具体代码 |
| return 结果 | 将结果返回,不能和void共存 |
4.4 有参无返回值方法
定义格式:
java
public static void 方法名(参数) {
方法体
}调用方式:直接调用
java
方法名(具体的值);代码示例:
java
public class MethodDemo02 {
public static void main(String[] args) {
add(10, 20);
}
public static void add(int a, int b) {
int sum = a + b;
System.out.println("和:" + sum);
}
}
4.5 无参有返回值方法
定义格式:
java
public static 返回值类型 方法名() {
方法体
return 结果;
}调用方式:
- 打印调用:
System.out.println(方法名()); - 赋值调用:
数据类型 变量名 = 方法名();
代码示例:
java
public class MethodDemo03 {
public static void main(String[] args) {
// 打印调用
System.out.println(add());
// 赋值调用
int result = add();
System.out.println("结果:" + result);
}
public static int add() {
int a = 10;
int b = 20;
int sum = a + b;
return sum;
}
}
4.6 有参有返回值方法 ⭐⭐⭐
定义格式:
java
public static 返回值类型 方法名(参数) {
方法体
return 结果;
}调用方式:
- 打印调用:
System.out.println(方法名(具体的值)); - 赋值调用:
数据类型 变量名 = 方法名(具体的值);
代码示例:
java
public class MethodDemo04 {
public static void main(String[] args) {
// 赋值调用
int result = add(10, 20);
System.out.println("结果:" + result);
}
public static int add(int a, int b) {
int sum = a + b;
return sum;
}
}
4.7 形参和实参
形式参数(形参):在定义方法时,形式上定义的参数,此时还没有具体的值
实际参数(实参):在调用方法时,给形参传递的具体的值
初学者建议:
- 先定义,再调用
- 没有返回值的 → 直接调用
- 有返回值的 → 赋值调用
4.8 参数和返回值的使用时机 ⭐⭐⭐
参数的使用时机:
- 当想将方法A中的数据传递到方法B中做操作时
- 方法B在定义时需要带参数,等着接收方法A中的数据
返回值的使用时机:
- 方法A调用方法B后,需要方法B的结果
- 拿到方法B的结果在A中做其他操作
- 此时方法B需要将自己的结果返回出去
代码示例:
java
public class MethodDemo05 {
public static void main(String[] args) {
int a = 10;
int b = 20;
int result = method(a, b);
if (result > 10) {
System.out.println("结果大于10");
} else {
System.out.println("结果不大于10");
}
}
public static int method(int a, int b) {
int sum = a + b;
return sum;
}
}
二、重点难点
2.1 冒泡排序的优化 ⭐⭐⭐
问题:标准冒泡排序即使数组已经有序,仍会继续比较
优化方案:添加标志位,如果某一轮没有发生交换,说明数组已经有序
java
public class BubbleSortOptimized {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
boolean swapped;
for (int i = 0; i < arr.length - 1; i++) {
swapped = false;
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;
swapped = true;
}
}
if (!swapped) {
break;
}
}
}
}2.2 二分查找的边界问题 ⭐⭐
常见错误:
- 循环条件写成
min < max,会漏掉最后一个元素 - 更新边界时写成
min = mid或max = mid,可能导致死循环
正确写法:
- 循环条件:
min <= max - 更新边界:
min = mid + 1或max = mid - 1
2.3 二维数组的内存理解 ⭐⭐
内存结构:
- 二维数组在栈中存储的是地址值
- 每个一维数组在堆中独立开辟空间
- 二维数组存储的是一维数组的地址
注意事项:
int[][] arr = new int[3][];此时一维数组还未创建- 访问未初始化的一维数组会抛出
NullPointerException
2.4 方法的返回值使用 ⭐⭐⭐
常见误区:
- 有返回值的方法没有接收返回值
- 在void方法中使用
return 值; - 有返回值的方法没有return语句
正确做法:
java
// 错误示例
public static int add(int a, int b) {
int sum = a + b;
System.out.println(sum); // 没有return
}
// 正确示例
public static int add(int a, int b) {
int sum = a + b;
return sum;
}三、常见面试题
3.1 冒泡排序的时间复杂度和空间复杂度是多少? ⭐⭐⭐
答案:
- 时间复杂度:
- 最好情况:O(n) - 数组已经有序,优化后的冒泡排序只需一轮
- 平均情况:O(n²)
- 最坏情况:O(n²) - 数组完全逆序
- 空间复杂度:O(1) - 只使用了常数级别的额外空间
追问:如何优化冒泡排序? 回答:添加标志位,如果某一轮没有发生交换,说明数组已经有序,可以提前结束排序。
3.2 二分查找为什么要求数组必须有序? ⭐⭐
答案: 二分查找的核心思想是每次比较中间元素,根据比较结果决定在左半部分还是右半部分继续查找。如果数组无序,无法确定目标值在左半部分还是右半部分,算法无法正常工作。
追问:如果数组无序,如何查找? 回答:可以使用顺序查找(时间复杂度O(n)),或者先排序再二分查找(排序时间复杂度O(n log n))。
3.3 Arrays.sort()使用的是什么排序算法? ⭐⭐⭐
答案:
- 对于基本类型数组(int[], double[]等):使用双轴快速排序(Dual-Pivot Quicksort)
- 对于对象数组(Integer[], String[]等):使用TimSort(归并排序的优化版本)
追问:为什么使用不同的排序算法? 回答:
- 基本类型不需要考虑稳定性,双轴快速排序性能更好
- 对象类型需要保证稳定性(相等元素的相对顺序不变),TimSort是稳定的
3.4 什么是方法的重载? ⭐⭐
答案: 方法重载是指在一个类中定义多个同名方法,但它们的参数列表不同(参数个数、参数类型或参数顺序不同)。
注意:
- 返回值类型不同不能作为重载的判断标准
- 参数名不同也不能作为重载的判断标准
示例:
java
public static int add(int a, int b) { return a + b; }
public static int add(int a, int b, int c) { return a + b + c; }
public static double add(double a, double b) { return a + b; }3.5 二维数组的length属性代表什么? ⭐
答案:
arr.length:二维数组中一维数组的个数arr[i].length:第i个一维数组的长度
3.6 如何理解Java中的值传递? ⭐⭐⭐
答案: Java中只有值传递,没有引用传递。
- 基本类型:传递的是值的副本
- 引用类型:传递的是地址值的副本
示例:
java
public static void main(String[] args) {
int[] arr = {1, 2, 3};
change(arr);
System.out.println(arr[0]); // 输出:10
}
public static void change(int[] arr) {
arr[0] = 10; // 修改的是同一个数组对象
}java
public static void main(String[] args) {
int a = 10;
change(a);
System.out.println(a); // 输出:10
}
public static void change(int a) {
a = 20; // 修改的是副本,不影响原变量
}3.7 手写冒泡排序和二分查找 ⭐⭐⭐
冒泡排序:
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;
}
}
}
}二分查找:
java
public static int binarySearch(int[] arr, int key) {
int min = 0;
int max = arr.length - 1;
while (min <= max) {
int mid = (min + max) / 2;
if (key > arr[mid]) {
min = mid + 1;
} else if (key < arr[mid]) {
max = mid - 1;
} else {
return mid;
}
}
return -1; // 未找到
}四、实用代码片段
4.1 数组工具方法集合
java
import java.util.Arrays;
public class ArrayUtils {
// 数组翻转
public static void reverse(int[] arr) {
for (int min = 0, max = arr.length - 1; min < max; min++, max--) {
int temp = arr[min];
arr[min] = arr[max];
arr[max] = temp;
}
}
// 冒泡排序
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;
}
}
}
}
// 二分查找
public static int binarySearch(int[] arr, int key) {
int min = 0;
int max = arr.length - 1;
while (min <= max) {
int mid = (min + max) / 2;
if (key > arr[mid]) {
min = mid + 1;
} else if (key < arr[mid]) {
max = mid - 1;
} else {
return mid;
}
}
return -1;
}
// 求数组最大值
public static int getMax(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 getMin(int[] arr) {
int min = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] < min) {
min = arr[i];
}
}
return min;
}
// 打印数组
public static void print(int[] arr) {
System.out.println(Arrays.toString(arr));
}
}4.2 二维数组工具方法
java
public class TwoArrayUtils {
// 遍历二维数组
public static void print(int[][] arr) {
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();
}
}
// 计算二维数组所有元素的和
public static int sum(int[][] arr) {
int sum = 0;
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
sum += arr[i][j];
}
}
return sum;
}
}4.3 常用方法示例
java
public class MethodExamples {
// 判断奇偶
public static boolean isOdd(int num) {
return num % 2 != 0;
}
// 判断素数
public static boolean isPrime(int num) {
if (num <= 1) return false;
for (int i = 2; i <= Math.sqrt(num); i++) {
if (num % i == 0) return false;
}
return true;
}
// 计算阶乘
public static long factorial(int n) {
if (n <= 1) return 1;
long result = 1;
for (int i = 2; i <= n; i++) {
result *= i;
}
return result;
}
// 计算幂
public static double power(double base, int exponent) {
return Math.pow(base, exponent);
}
}五、经典练习题
5.1 基础题
练习1:数组元素求和
题目:定义一个方法,接收一个整数数组,返回数组所有元素的和。
java
public static int getSum(int[] arr) {
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum;
}练习2:数组平均值
题目:定义一个方法,接收一个整数数组,返回数组元素的平均值。
java
public static double getAverage(int[] arr) {
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
return (double) sum / arr.length;
}练习3:查找元素索引
题目:定义一个方法,接收一个整数数组和目标值,返回目标值在数组中第一次出现的索引,如果不存在返回-1。
java
public static int indexOf(int[] arr, int key) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] == key) {
return i;
}
}
return -1;
}5.2 进阶题
练习4:选择排序
题目:实现选择排序算法。
思路:每次从未排序部分选择最小元素,放到已排序部分的末尾。
java
public static void selectionSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
int minIndex = i;
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
if (minIndex != i) {
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
}练习5:杨辉三角
题目:使用二维数组打印杨辉三角的前10行。
java
public static void printPascalTriangle(int n) {
int[][] arr = new int[n][];
for (int i = 0; i < n; i++) {
arr[i] = new int[i + 1];
arr[i][0] = 1;
arr[i][i] = 1;
for (int j = 1; j < i; j++) {
arr[i][j] = arr[i - 1][j - 1] + arr[i - 1][j];
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j <= i; j++) {
System.out.print(arr[i][j] + " ");
}
System.out.println();
}
}练习6:数组去重
题目:定义一个方法,去除数组中的重复元素。
java
public static int[] removeDuplicates(int[] arr) {
int[] temp = new int[arr.length];
int size = 0;
for (int i = 0; i < arr.length; i++) {
boolean isDuplicate = false;
for (int j = 0; j < size; j++) {
if (arr[i] == temp[j]) {
isDuplicate = true;
break;
}
}
if (!isDuplicate) {
temp[size++] = arr[i];
}
}
int[] result = new int[size];
System.arraycopy(temp, 0, result, 0, size);
return result;
}5.3 挑战题
练习7:实现Arrays.toString方法
题目:不使用Arrays.toString,自己实现数组转字符串的方法。
java
public static String myToString(int[] arr) {
if (arr == null) return "null";
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < arr.length; i++) {
sb.append(arr[i]);
if (i < arr.length - 1) {
sb.append(", ");
}
}
sb.append("]");
return sb.toString();
}练习8:二维数组对角线求和
题目:计算二维数组两条对角线元素的和。
java
public static void diagonalSum(int[][] arr) {
int sum1 = 0; // 主对角线
int sum2 = 0; // 副对角线
for (int i = 0; i < arr.length; i++) {
sum1 += arr[i][i];
sum2 += arr[i][arr.length - 1 - i];
}
System.out.println("主对角线和:" + sum1);
System.out.println("副对角线和:" + sum2);
}