【java常用API】----- Arrays

1. Arrays类简介

Arrays 类位于 java.util 包下,是一个专门用于操作数组的工具类。由于数组是编程中最基础的数据结构之一,Arrays 提供了大量静态方法来简化数组的常见操作,例如排序、搜索、填充和转换等。

核心特点:

  • 该类包含的方法均为 静态方法 ,无需实例化对象,直接通过 Arrays.方法名() 调用。

2. Arrays 类的常用方法概览

下表列出了 Arrays 类中最核心、最常用的方法及其功能说明:

方法名 说明
public static String toString(数组) 将数组的内容拼接成一个格式化的字符串,便于打印查看。
public static int binarySearch(数组, 查找的元素) 使用二分查找法在数组中查找指定元素,返回其索引。
public static int[] copyOf(原数组, 新数组长度) 拷贝数组,可以指定新数组的长度(支持扩容或截断)。
public static int[] copyOfRange(原数组, 起始索引, 结束索引) 拷贝数组的指定范围(左闭右开)。
public static void fill(数组, 元素) 将数组中的所有元素填充为指定的值。
public static void sort(数组) 对数组进行自然排序(默认升序)。
public static void sort(数组, 排序规则) 根据指定的比较器规则对数组进行排序。

3. 常用方法详解与演示

3.1 toString 方法:数组转字符串

直接打印数组对象默认输出的是哈希地址,而 toString 方法可以将数组内容转换为易读的字符串格式(例如 [1, 2, 3])。

java 复制代码
package com.example;
import java.util.Arrays;

public class ArraysDemo {
    public static void main(String[] args) {
        // toString: 将数组变成字符串
        System.out.println("-----------------toString-----------------");
        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        // 直接打印数组对象得到的是地址,使用 Arrays.toString 得到内容
        System.out.println(Arrays.toString(arr));
        // 输出结果: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    }
}

3.2 binarySearch 方法:二分查找

二分查找(Binary Search)是一种在有序数组中查找特定元素的高效算法,其时间复杂度为 O(log⁡n)O(\log n)O(logn)。

⚠️ 使用前提:

调用 binarySearch 方法前,必须保证数组已经是有序的 (通常是升序)。如果数组未排序,必须先调用 Arrays.sort() 进行排序,否则查找结果是不确定的。

3.2.1 返回值规则详解:

  1. 元素存在: 返回该元素在数组中的 真实索引 (≥0\ge 0≥0)。
  2. 元素不存在: 返回 -(插入点) - 1
    • 插入点:指该元素如果要插入数组以保持有序,应该所在的位置索引。

3.2.2 为什么要返回 -(插入点) - 1

这是为了在返回值上区分"找到了"和"没找到",同时又能提供有用的信息。

  • 如果仅仅返回 -插入点,当元素应该插入在索引 0 时,返回值为 -0(即 0)。
  • 这就与"元素正好在索引 0 处被找到"的情况(返回值也是 0)产生了冲突。
  • 因此,Java 规定返回负数来表示未找到,公式 -(插入点) - 1 既保证了结果恒为负数,又可以通过计算反推出该元素应该插入的位置。
java 复制代码
package com.example;
import java.util.Arrays;

public class ArraysDemo {
    public static void main(String[] args) {
        // arr 已经是升序数组 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

        System.out.println("-----------------binarySearch-----------------");
        // 1. 查找存在的元素:返回真实索引
        System.out.println(Arrays.binarySearch(arr, 10)); // 输出: 9 (索引为9)
        System.out.println(Arrays.binarySearch(arr, 2));  // 输出: 1 (索引为1)

        // 2. 查找不存在的元素:返回 -(插入点) - 1
        // 元素 20 比数组中所有元素都大,应该插入在索引 10 的位置
        // 计算:-(10) - 1 = -11
        System.out.println(Arrays.binarySearch(arr, 20)); // 输出: -11
    }
}

3.3 copyOfcopyOfRange:数组拷贝

在实际开发中,我们经常需要对数组进行扩容截取Arrays 提供了两个非常便捷的方法来实现这一功能。

3.3.1 copyOf 方法:全量复制与扩容

Arrays.copyOf 方法主要用于复制整个数组。它允许我们指定新数组的长度,从而轻松实现数组的扩容截断

💡 核心机制:

  • 扩容 :如果指定的 newLength 大于原数组长度,新数组多出的部分会自动填充该数据类型的默认初始化值 (例如 int 类型为 0,引用类型为 null)。
  • 截断 :如果指定的 newLength 小于原数组长度,新数组将只保留原数组的前 newLength 个元素,多余部分被丢弃。
java 复制代码
package com.example;
import java.util.Arrays;

public class ArraysDemo {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        System.out.println("--------------------copyOf--------------------");
        // 场景:数组扩容
        // 将数组长度从 10 扩展到 20
        int[] newArr1 = Arrays.copyOf(arr, 20);
        // 输出结果:原数据保留,后10位自动补0
        System.out.println(Arrays.toString(newArr1));
        // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

        // 场景:数组截断
        // 将数组长度从 10 截断为 5
        int[] newArr2 = Arrays.copyOf(arr, 5);
        // 输出结果:只保留前 5 个元素
        System.out.println(Arrays.toString(newArr2));
        // [1, 2, 3, 4, 5]
    }
}

3.3.2 copyOfRange 方法:指定范围拷贝

如果你只需要数组中的某一部分数据,Arrays.copyOfRange 是最佳选择。它允许你通过指定索引范围来提取数组的片段。

⚠️ 关键细节:

  • 区间规则 :遵循 "左闭右开" 原则,即 [from, to)
  • 包含 :起始索引 from 对应的元素。
  • 不包含 :结束索引 to 对应的元素(即复制到 to - 1 为止)。
java 复制代码
package com.example;
import java.util.Arrays;

public class ArraysDemo {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        System.out.println("--------------------copyOfRange--------------------");
        // 场景:截取数组片段
        // 截取索引 0 到 9 的元素(不包含索引 9 的元素)
        int[] newArr2 = Arrays.copyOfRange(arr, 0, 9);
        // 输出结果:只包含索引 0~8 的元素
        System.out.println(Arrays.toString(newArr2));
        // [1, 2, 3, 4, 5, 6, 7, 8, 9]
    }
}

3.4 fill 方法:填充数组

如果需要将数组中的所有元素快速替换为同一个值,可以使用 fill 方法。

⚠️ 注意: 该操作是直接修改原数组的内容,没有返回值(void)。

java 复制代码
package com.example;
import java.util.Arrays;

public class ArraysDemo {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        // fill: 填充数组
        System.out.println("--------------------fill--------------------");
        // 将 arr 数组中的所有元素都填充为 100
        Arrays.fill(arr, 100);
        System.out.println(Arrays.toString(arr));
        // 输出结果: [100, 100, 100, 100, 100, 100, 100, 100, 100, 100]
    }
}

3.5 sort 方法:数组排序

Arrays.sort 是 Java 中最常用的排序工具。根据数据类型的不同,它提供了基本类型排序对象类型定制排序两种模式。

3.5.1 基本类型排序(自然排序)

对于 intdoublechar 等基本数据类型的数组,直接调用 sort(array) 即可。

  • 规则 :按照数值的升序(从小到大)排列。
  • 底层算法:使用的是经过优化的快速排序算法(Dual-Pivot Quicksort),性能极高。
java 复制代码
package com.example;
import java.util.Arrays;

public class ArraysDemo {
    public static void main(String[] args) {
        System.out.println("-----------------Sort Basic-----------------");
        int[] arr = {10, 2, 3, 5, 6, 1, 7, 8, 4, 9};
        // 直接排序,默认升序
        Arrays.sort(arr);
        // 输出结果: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        System.out.println(Arrays.toString(arr));
    }
}

3.5.2 对象类型排序(定制排序)

对于对象数组(如 Integer[]String[] 或自定义对象),如果需要降序特殊规则 排序,则需要传入第二个参数:Comparator(比较器)。

⚠️ 重要提示:

基本数据类型(如 int[])不支持 Comparator 排序。如果要使用比较器,必须使用对应的包装类数组(如 Integer[])。

3.5.2.1 核心逻辑:compare 方法的返回值

Comparator 接口中的 compare(T o1, T o2) 方法决定了排序的顺序。你可以将其理解为 o1o2 的"PK"规则,返回值决定了它们的位置关系:

返回值 含义 结果
负数 (< 0) o1 小于 o2 o1 排在 o2 前面(不交换)
正数 (> 0) o1 大于 o2 o1 排在 o2 后面(交换位置)
(= 0) o1 等于 o2 位置不变

如何实现升序与降序?

  • 升序(小 -> 大): 使用 o1 - o2
    • 如果 o1o2 大,结果为正数,o1 会被扔到后面去。
  • 降序(大 -> 小): 使用 o2 - o1
    • 如果 o1o2 大,结果为负数,o1 会留在前面。
3.5.2.2 代码演示:匿名内部类(传统写法)
java 复制代码
package com.example;
import java.util.Arrays;
import java.util.Comparator;

public class ArraysDemo {
    public static void main(String[] args) {
        System.out.println("-----------------Sort Descending-----------------");
        // 注意:必须使用包装类 Integer[],不能用 int[]
        Integer[] arrObj = {2, -3, 1, 5, 6, 7, 6, 4, 9};
        // 需求:降序排列 (大 -> 小)
        Arrays.sort(arrObj, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                // o2 - o1 表示降序
                return o2 - o1;
            }
        });
        // 输出结果: [9, 7, 6, 6, 5, 4, 2, 1, -3]
        System.out.println(Arrays.toString(arrObj));
    }
}
3.5.2.3 代码演示:Lambda 表达式(Java 8+ 推荐写法)

Lambda 表达式可以让代码更加简洁。

java 复制代码
package com.example;
import java.util.Arrays;
import java.util.Comparator;

public class ArraysDemo {
    public static void main(String[] args) {
        System.out.println("-----------------Sort Descending-----------------");
        // 注意:必须使用包装类 Integer[],不能用 int[]
        Integer[] arrObj = {2, -3, 1, 5, 6, 7, 6, 4, 9};
        // 需求:升序排列 (大 -> 小)
        //lambda 表达式 简化 匿名内部类
        Arrays.sort(arrObj, (o1, o2) -> o2 - o1);

        // 输出结果: [9, 7, 6, 6, 5, 4, 2, 1, -3]
        System.out.println(Arrays.toString(arrObj));
    }
}

3.5.3 进阶技巧:规避整数溢出风险

在上一节中,我们使用了 o2 - o1 的方式进行降序排序 。虽然写法简单,但在处理极端数值时,这种写法存在致命缺陷------整数溢出(Integer Overflow)

为什么减法运算存在隐患?

Java 中 int 的取值范围约为 -21亿21亿

  • 场景模拟 :假设 o2 是一个很大的正数(如 20亿),o1 是一个绝对值很大的负数(如 -20亿)。
  • 数学计算 :20亿−(−20亿)=40亿20亿 - (-20亿) = 40亿20亿−(−20亿)=40亿。
  • 实际结果int 类型无法存储 40亿,数值会发生溢出 ,结果会变成一个负数
  • 致命后果 :排序算法会误以为 o1 小于 o2,导致排序逻辑完全混乱。
官方推荐的稳健写法

为了解决这个问题,Java 官方推荐使用 Integer.compare(x, y) 方法。它内部采用逻辑判断(If-Else)而非数值相减,彻底规避了溢出风险,是生产环境中的标准写法。

排序需求 减法写法 (不推荐) 官方标准写法 (推荐) 逻辑含义
升序 (从小到大) o1 - o2 Integer.compare(o1, o2) o1 与 o2 比较
降序 (从大到小) o2 - o1 Integer.compare(o2, o1) o2 与 o1 比较

💡 核心口诀

  • 升序compare(o1, o2)
  • 降序compare(o2, o1)
代码演示:降序场景下的对比

为了验证效果,我们构造一组包含极大值和极小值的数据进行降序排序测试。

java 复制代码
package com.example;
import java.util.Arrays;

public class ArraysDemo {
    public static void main(String[] args) {
        System.out.println("-----------------Compare Demo-----------------");
        
        // 构造极端数据:包含最大正值和最小负值,极易触发溢出
        Integer[] arr = {1, -300, -2000000000, 2000000000};

        // 1. 【错误示范】使用减法实现降序
        // 风险点:当计算 (-20亿) - (20亿) 时,结果 -40亿 会溢出变为正数
        Arrays.sort(arr, (o1, o2) -> o2 - o1);
        System.out.println("减法排序结果 (潜在风险): " + Arrays.toString(arr));

        // 重置数据
        arr = new Integer[]{1, -300, -2000000000, 2000000000};

        // 2. 【正确示范】使用 Integer.compare 实现降序
        // 优势:内部逻辑判断,绝对安全,结果准确
        Arrays.sort(arr, (o1, o2) -> Integer.compare(o2, o1));
        System.out.println("compare排序结果 (安全稳健): " + Arrays.toString(arr));
    }
}

相关推荐
不会写DN2 小时前
PHP 中的文件读写与上传
android·开发语言·php
LuckyTHP3 小时前
迁移shibboleth java获取shibboleth用户信息
java·开发语言
客卿1233 小时前
数论===质数统计(暴力法,)
java·开发语言
Σίσυφος19003 小时前
C++ 多肽经典面试题
开发语言·c++·面试
华科易迅3 小时前
Spring 事务(注解)
java·数据库·spring
写代码的小阿帆3 小时前
Web工程结构解析:从MVC分层到DDD领域驱动
java·架构·mvc
东离与糖宝4 小时前
Java 26+Spring Boot 3.5,微服务启动从3秒压到0.8秒
java·人工智能
csdn_aspnet4 小时前
C# 求n边凸多边形的对角线数量(Find number of diagonals in n sided convex polygon)
开发语言·算法·c#
禹中一只鱼4 小时前
【力扣热题100学习笔记】 - 哈希
java·学习·leetcode·哈希算法