一、数组的基本概念
数组是计算机科学中最基础且重要的数据结构之一,它是由相同数据类型元素构成的有序集合。下面详细说明数组的主要特性:
1. 数据类型一致性
数组中的所有元素必须是相同的数据类型(如整型、浮点型、字符型等),这种特性使得编译器可以更高效地管理内存和进行类型检查。
- 示例:
int[] numbers = {1, 2, 3}
是正确的,而{1, "hello", 3.14}
则会引发类型错误 - 内存优势:相同数据类型意味着每个元素占用的内存大小一致,便于计算偏移量
- 编译时检查:大多数编程语言会在编译时检查数组元素的类型一致性
- 性能影响:避免了运行时类型检查的开销,提高了访问效率
2. 有序索引访问
数组元素通过从0开始的整数索引进行访问,这种机制提供了快速随机访问的能力。
- 访问语法:
arrayName[index]
,如numbers[0]
获取第一个元素 - 索引范围:0 到
length-1
,超出范围会抛出ArrayIndexOutOfBoundsException
- 示例:长度为5的数组,有效索引是0-4
- 多维数组:可以通过多个索引访问,如
matrix[1][2]
- 负索引:某些语言(如Python)支持负索引,-1表示最后一个元素
- 边界检查:现代语言通常会自动进行边界检查,防止越界访问
3. 固定长度特性
数组在创建时必须指定长度(如int[10]
),一旦创建,其长度不可改变(静态数据结构)。
- 初始化方式:
- 显式指定长度:
int[] arr = new int[5]
- 通过初始化列表:
int[] arr = {1, 2, 3}
- 显式指定长度:
- 长度不可变性:
- 无法直接扩展或收缩数组
- 需要更大空间时,必须创建新数组并复制元素
- 动态数组替代方案:
- Java的
ArrayList
,C++的vector
- JavaScript的
Array
(实际是动态数组)
- Java的
- 应用考虑:
- 通常会预估所需最大空间来初始化数组
- 内存受限系统中,固定大小有助于内存管理
4. 连续内存存储
数组元素在内存中是连续存储的,这种布局带来了显著的性能优势。
- 访问效率:
- 时间复杂度为O(1),可以通过首地址+偏移量直接定位
- 偏移量计算:
元素地址 = 首地址 + 索引 × 元素大小
- 缓存友好性:
- 连续内存访问模式能充分利用CPU缓存
- 对比链表等结构,减少了缓存未命中
- 硬件优化:
- 现代CPU针对连续内存访问有专门优化
- 支持SIMD指令进行并行处理
- 内存布局示例:
int[] arr = {10,20,30};
- 内存地址:0x1000(10), 0x1004(20), 0x1008(30)(假设int占4字节)
5. 典型应用场景
数组的诸多特性使其在各种领域都有广泛应用。
- 图像处理:
- 像素矩阵表示(RGB值数组)
- 卷积运算中的核矩阵
- 游戏开发:
- 地图数据存储(瓦片地图)
- 角色属性数组
- 科学计算:
- 向量/矩阵存储
- 数值分析中的数据集
- 数据库系统:
- 记录集合的底层存储
- 索引结构的实现
- 操作系统:
- 文件描述符表
- 进程控制块数组
6. 高级语言实现特性
现代高级语言中的数组实现通常会包含额外的功能和支持。
- 元数据信息:
- 长度属性(如Java的
length
,C#的Length
) - 类型信息(用于运行时检查)
- 长度属性(如Java的
- 安全特性:
- 自动边界检查
- 空引用检查
- 便利方法:
- 排序、搜索等内置方法
- 迭代器支持
- 多维支持:
- 锯齿数组(数组的数组)
- 真正的多维数组(连续内存块)
- 语言差异:
- C/C++:更接近原始内存操作
- Java/C#:完全的对象封装
- Python:实际上是动态数组
二、数组的声明
在 Java 中,数组的声明是创建数组的第一步,主要有以下两种语法格式:
-
第一种声明方式(推荐使用):
数据类型[] 数组名;
例如:
int[] scores; // 声明一个整型数组,用于存储成绩 String[] names; // 声明一个字符串数组,用于存储姓名
这种写法更符合 Java 的编程习惯,将数组类型和变量名分开,能更清晰地表达这是一个数组类型的变量。
-
第二种声明方式:
数据类型 数组名[];
例如:
double prices[]; // 声明一个双精度浮点型数组 char letters[]; // 声明一个字符数组
这种语法源自 C/C++ 语言,虽然 Java 允许这种写法,但在实际开发中不太推荐使用。
重要注意事项:
- 数组声明只是定义了一个可以指向数组的引用变量,此时并没有为数组元素分配内存空间
- 数组变量默认初始化为 null
- 数组的大小不是在声明时确定的,而是在创建数组对象时确定的
- 在实际开发中,通常会结合数组的初始化一起使用,例如:
int[] numbers = new int[5]; // 声明并创建一个长度为5的整型数组 String[] weekDays = {"Mon", "Tue", "Wed", "Thu", "Fri"}; // 声明并初始化数组
推荐使用第一种声明方式的原因:
- 类型信息更集中,便于阅读和理解
- 与Java集合框架的声明风格保持一致
- 在同时声明多个数组变量时更清晰,例如:
int[] arr1, arr2; // 两个都是数组 int arr3[], arr4; // 只有arr3是数组,arr4是普通int变量
三、数组的初始化
概述
数组初始化是Java编程中的基础操作,它为数组分配内存空间并赋予初始值。数组初始化在Java中主要有三种方式,每种方式都有其特定的使用场景和语法规则。
静态初始化
静态初始化是在声明数组的同时直接为数组元素赋值的初始化方式,编译器会根据提供的元素数量自动确定数组长度。这种方式适用于在创建数组时就已经知道所有元素值的情况。
完整语法形式
数据类型[] 数组名 = new 数据类型[]{元素1, 元素2, ..., 元素n};
简化语法形式
数据类型[] 数组名 = {元素1, 元素2, ..., 元素n};
示例代码
// 完整形式
int[] scores = new int[]{90, 85, 78, 92, 88};
String[] names = new String[]{"Alice", "Bob", "Charlie"};
// 简化形式
double[] prices = {19.99, 29.99, 39.99};
char[] vowels = {'a', 'e', 'i', 'o', 'u'};
动态初始化
动态初始化是先指定数组长度,由系统为数组元素赋予默认值,随后再手动为元素赋值的初始化方式。这种方式适用于数组长度已知但元素值需要后续计算或从外部获取的情况。
语法形式
数据类型[] 数组名 = new 数据类型[数组长度];
各数据类型的默认值
数据类型 | 默认值 |
---|---|
byte, short, int, long | 0 |
float, double | 0.0 |
char | '\u0000' |
boolean | false |
引用类型 | null |
示例代码
// 创建长度为5的整型数组,默认值为0
int[] numbers = new int[5];
numbers[0] = 10;
numbers[1] = 20;
numbers[2] = 30;
// 创建长度为3的字符串数组,默认值为null
String[] cities = new String[3];
cities[0] = "Beijing";
cities[1] = "Shanghai";
cities[2] = "Guangzhou";
// 创建二维数组
int[][] matrix = new int[3][4];
matrix[0][0] = 1;
matrix[1][1] = 2;
注意事项
-
混合初始化错误:不能同时使用静态和动态初始化,例如:
// 错误示例 int[] arr = new int[3]{1,2,3}; // 编译错误
-
数组长度不可变:数组一旦初始化完成,其长度就固定不变。如果需要改变长度,必须创建新的数组:
int[] original = {1, 2, 3}; int[] expanded = new int[5]; System.arraycopy(original, 0, expanded, 0, original.length);
-
数组越界:访问数组时要确保索引在有效范围内(0到length-1),否则会抛出ArrayIndexOutOfBoundsException。
-
空指针异常:对于引用类型数组,元素默认值为null,直接操作null元素会导致NullPointerException。
-
数组初始化后:无论采用哪种初始化方式,数组创建后就可以通过索引访问和修改其中的元素。
四、数组的访问
索引访问机制
数组元素访问是通过索引来实现的,索引表示元素在数组中的位置。语法为:数组名[索引],其中索引必须是整数值。在大多数编程语言中,数组索引都是从0开始计算的,这种设计源于计算机内存寻址方式,使得计算元素地址更加高效。
具体示例
以Java语言为例:
int[] arr = {1, 2, 3}; // 声明并初始化一个包含3个元素的整型数组
System.out.println(arr[0]); // 访问数组的第一个元素,输出1
arr[1] = 5; // 修改数组的第二个元素的值为5
System.out.println(arr[1]); // 现在会输出5
索引范围与安全访问
索引范围规则
- 数组的索引范围是从0开始,到数组长度减1结束
- 例如,长度为3的数组,有效索引是0、1、2
- 如果访问的索引超出有效范围,会抛出ArrayIndexOutOfBoundsException异常
无效访问示例
arr[3] // 会抛出异常,因为索引3超出了有效范围(0-2)
不同语言的差异
- C/C++中访问越界可能不会立即报错,但会导致未定义行为
- Python中使用负索引可以访问数组末尾的元素,如arr[-1]表示最后一个元素
- JavaScript会自动扩展数组长度来处理越界赋值
安全访问实践
建议的安全访问模式:
// 先检查索引是否有效
if (index >= 0 && index < arr.length) {
// 安全的数组访问
System.out.println(arr[index]);
} else {
System.out.println("无效的数组索引");
}
性能特点
数组的这种连续存储和索引访问方式使其在随机访问元素时非常高效:
- 时间复杂度为O(1)
- 内存访问模式对缓存友好
- 地址计算公式:元素地址 = 数组首地址 + (索引 × 元素大小)
多维数组访问
对于多维数组,访问方式类似但需要多个索引:
int[][] matrix = {{1,2}, {3,4}};
System.out.println(matrix[1][0]); // 输出3
常见应用场景
- 快速查找:通过索引直接定位元素
- 数据缓冲:需要连续存储空间时
- 算法实现:如排序、搜索等基础算法
- 图像处理:像素数据存储
五、数组的长度
在 Java 中,数组的 length 属性是一个非常重要的特性,它提供了获取数组容量的标准方法。与其他集合类不同,数组是一个固定长度的数据结构,其 length 属性是在数组创建时就确定的,且在整个生命周期中保持不变。
详细语法说明
获取数组长度的标准语法格式为:
数组名.length
这个 length 属性具有以下关键特性:
- 它是一个 final 字段(final field),不是方法,因此使用时不需要加括号
- 对于一维数组,它返回数组包含的元素个数
- 对于多维数组,它返回第一维的大小
- 数组长度一旦确定就不能改变,这是数组与集合类(如 ArrayList)的重要区别
多维数组的特殊处理
对于多维数组,length 的行为需要特别注意:
int[][] matrix = new int[3][4];
matrix.length
返回 3(第一维的长度)matrix[0].length
返回 4(第二维的长度)- 对于不规则数组(ragged array),每一行的长度可能不同
实际应用场景详解
-
数组遍历: 这是最常用的场景,确保不会出现数组越界异常
for(int i = 0; i < arr.length; i++) { // 安全访问 }
-
数组拷贝: 在 System.arraycopy() 或 Arrays.copyOf() 中确定目标数组大小
int[] copy = new int[original.length];
-
边界检查: 在执行数组操作前进行有效性验证
if(index >= 0 && index < arr.length) { // 安全操作 }
-
数组初始化: 根据已知数组长度创建新数组
String[] names = new String[sourceArray.length];
典型错误示例
-
错误地将 length 当作方法调用:
int len = arr.length(); // 编译错误
-
忽略多维数组的层次结构:
int[][] matrix = new int[3][]; System.out.println(matrix[0].length); // NullPointerException
-
假设数组长度可变:
arr.length = 10; // 编译错误,length 是 final 的
与集合类的 size() 方法对比
特性 | 数组 length | 集合 size() |
---|---|---|
语法 | 属性 | 方法 |
可变性 | 固定 | 可变 |
获取方式 | 直接访问 | 方法调用 |
多维结构 | 分层获取 | 统一获取 |
性能考虑
length 属性的访问是直接的内存读取操作,具有 O(1) 的时间复杂度,比集合类的 size() 方法更高效,因为:
- 不需要方法调用开销
- 不需要额外的计算
- 直接访问数组的元数据
最佳实践建议
-
在循环条件中使用 length 属性时,建议将其缓存到局部变量(特别是对于大数组):
int len = arr.length; for(int i = 0; i < len; i++) {...}
-
对于多维数组操作,确保对每一维都进行 length 检查:
for(int i = 0; i < matrix.length; i++) { for(int j = 0; j < matrix[i].length; j++) {...} }
-
在方法参数中传递数组时,总是考虑添加 length 参数以增加灵活性:
void processArray(int[] arr, int length) {...}
通过这些深入理解和正确应用,可以充分发挥 Java 数组 length 属性的优势,编写出更高效、更安全的数组操作代码。
六、数组的遍历
数组遍历是编程中最基础且重要的操作之一,它允许我们依次访问数组中的每个元素进行处理。根据不同的需求和场景,我们可以选择不同的遍历方式。
6.1 for 循环遍历
for 循环是最传统也是最灵活的数组遍历方式,它通过索引来访问数组元素。这种方式的优势在于可以精确控制遍历过程,并能够获取当前元素的索引位置。
基本语法:
for (初始化语句; 循环条件; 迭代语句) {
// 循环体
}
具体示例:
int[] arr = {1, 2, 3, 4, 5};
for (int i = 0; i < arr.length; i++) {
System.out.println("索引 " + i + " 处的元素是: " + arr[i]);
}
特点与应用场景:
- 精确控制:可以访问和修改任意位置的元素
- 索引可用:可以获取当前元素的索引值
- 灵活遍历:可以控制遍历顺序(正序、倒序)和步长
- 适合场景:需要修改数组元素、需要访问特定索引、需要跳过某些元素等情况
6.2 增强 for 循环(foreach 循环)
增强 for 循环是 Java 5 引入的语法糖,专门为集合和数组遍历设计,代码更加简洁易读。
基本语法:
for (数据类型 变量名 : 数组或集合) {
// 循环体,变量名表示当前遍历到的元素
}
具体示例:
int[] arr = {1, 2, 3, 4, 5};
for (int num : arr) {
System.out.println("当前元素是: " + num);
}
特点与应用场景:
- 简洁性:语法简单,代码量少
- 只读性:只能访问元素,不能直接修改原数组
- 无索引:不能获取当前元素的索引
- 适合场景:只需要读取数组元素而不需要修改、不需要知道元素索引的情况
注意事项:
- 增强 for 循环内部不能修改数组元素的值(修改的是局部变量的副本)
- 不能用于反向遍历数组
- 在遍历过程中不能跳过某些元素
两种遍历方式的比较
特性 | for 循环 | 增强 for 循环 |
---|---|---|
索引访问 | 支持 | 不支持 |
元素修改 | 支持 | 不支持 |
反向遍历 | 支持 | 不支持 |
代码简洁性 | 一般 | 优秀 |
性能 | 基本相当 | 基本相当 |
在实际开发中,应根据具体需求选择合适的遍历方式。当需要更精细的控制时使用传统 for 循环,当只需要简单遍历时使用增强 for 循环可以提高代码可读性。
七、数组的常见操作
7.1 数组的复制
7.1.1 System.arraycopy()方法
System.arraycopy()
是Java中用于数组复制的高效方法,其语法结构为:
System.arraycopy(源数组, 源数组起始索引, 目标数组, 目标数组起始索引, 复制长度);
参数说明:
- 源数组:需要被复制的原始数组
- 源数组起始索引:从源数组的哪个位置开始复制
- 目标数组:接收复制内容的目标数组
- 目标数组起始索引:从目标数组的哪个位置开始存放
- 复制长度:要复制的元素个数
示例分析:
int[] srcArr = {1, 2, 3, 4, 5};
int[] destArr = new int[5];
System.arraycopy(srcArr, 1, destArr, 2, 2);
该操作将:
- 从srcArr索引1的位置(值为2)开始
- 复制2个元素(即2和3)
- 放入destArr从索引2开始的位置
- 复制后destArr的内容为[0, 0, 2, 3, 0]
注意事项:
- 必须确保目标数组有足够的空间
- 源数组和目标数组可以是同一个数组,实现数组内元素的移动
- 如果参数不合法会抛出IndexOutOfBoundsException或ArrayStoreException
7.1.2 Arrays.copyOf()方法
Arrays.copyOf()
提供了另一种数组复制方式,语法为:
数据类型[] 新数组名 = Arrays.copyOf(源数组, 新长度);
特点:
- 总是返回一个新数组
- 新长度可以大于或小于原数组长度
- 新长度大于原长度时,多余元素填充默认值
- 新长度小于原长度时,只复制前面部分
示例扩展:
import java.util.Arrays;
int[] srcArr = {1, 2, 3};
// 扩展数组长度
int[] destArr1 = Arrays.copyOf(srcArr, 5);
// 结果:[1, 2, 3, 0, 0]
// 缩短数组长度
int[] destArr2 = Arrays.copyOf(srcArr, 2);
// 结果:[1, 2]
// 复制对象数组
String[] strArr = {"A", "B", "C"};
String[] newStrArr = Arrays.copyOf(strArr, 4);
// 结果:["A", "B", "C", null]
应用场景:
- 需要调整数组大小时
- 需要创建数组副本时
- 需要部分复制数组时
7.2 数组的排序
Java提供了Arrays.sort()
方法对数组进行排序,默认是升序排列。
基本排序示例
import java.util.Arrays;
int[] arr = {3, 1, 4, 2};
Arrays.sort(arr);
// 排序后:[1, 2, 3, 4]
字符数组排序
char[] charArr = {'c', 'a', 'b', 'A', 'B'};
Arrays.sort(charArr);
// 排序后:['A', 'B', 'a', 'b', 'c']
// 按照Unicode码点值排序
对象数组排序
String[] strArr = {"banana", "apple", "Orange"};
Arrays.sort(strArr);
// 排序后:["Orange", "apple", "banana"]
// 注意:默认区分大小写
部分排序
int[] arr = {5, 3, 1, 4, 2};
Arrays.sort(arr, 1, 4); // 对索引1到3(不包括4)的元素排序
// 结果:[5, 1, 3, 4, 2]
7.3 数组的查找
Arrays.binarySearch()
方法用于在已排序的数组中执行二分查找。
基本用法
int 索引 = Arrays.binarySearch(数组, 目标元素);
返回值说明:
- 找到元素:返回该元素的索引
- 未找到元素:返回一个负数,其值为-(插入点)-1
示例分析
import java.util.Arrays;
int[] arr = {1, 2, 3, 4, 5};
// 查找存在的元素
int index1 = Arrays.binarySearch(arr, 3);
// 返回2,因为3在索引2的位置
// 查找不存在的元素
int index2 = Arrays.binarySearch(arr, 6);
// 返回-6,因为:
// 插入点应为5
// -(5)-1 = -6
注意事项
- 数组必须已排序:对未排序数组使用可能导致错误结果
- 重复元素:如果有多个相同元素,不能保证返回哪个的索引
- 范围查找:可以指定查找范围
int index = Arrays.binarySearch(arr, 1, 4, 3); // 在索引1到3的子数组中查找3
实际应用
// 检查元素是否存在
int[] sortedArr = {10, 20, 30, 40, 50};
int searchKey = 30;
int result = Arrays.binarySearch(sortedArr, searchKey);
if (result >= 0) {
System.out.println("找到元素,索引:" + result);
} else {
System.out.println("未找到元素,可以插入的位置:" + (-result-1));
}
八、多维数组
在Java中,多维数组实际上是数组的数组,其中最常见的是二维数组。二维数组可以形象地理解为由行和列组成的表格结构,其中每个元素通过行索引和列索引来定位。
8.1 二维数组的声明和初始化
声明方式
Java提供了三种声明二维数组的语法,但第一种是最推荐使用的:
-
数据类型[][] 数组名;
(推荐)- 清晰表明这是一个二维数组
- 例如:
int[][] matrix;
-
数据类型 数组名[][];
- 类似C语言的声明方式
- 例如:
double matrix[][];
-
数据类型[] 数组名[];
(不推荐)- 可读性差,容易造成混淆
- 例如:
String[] names[];
初始化方式
静态初始化
静态初始化在声明时直接指定数组元素的值:
// 方式1:直接初始化
int[][] arr1 = {
{1, 2}, // 第一行2个元素
{3, 4, 5}, // 第二行3个元素
{6} // 第三行1个元素
};
// 方式2:使用new关键字
int[][] arr2 = new int[][]{
{10, 20},
{30, 40, 50}
};
静态初始化的特点:
- 不需要指定数组维度
- 每行的列数可以不同(不规则数组)
- 初始化数据一目了然
动态初始化
动态初始化先分配空间,后赋值:
// 方式1:固定行列数
int[][] arr3 = new int[3][4]; // 3行4列的矩阵
// 默认值:int类型为0,对象类型为null
// 方式2:动态指定列数
int[][] arr4 = new int[3][]; // 只指定行数
arr4[0] = new int[2]; // 第一行2列
arr4[1] = new int[3]; // 第二行3列
arr4[2] = new int[1]; // 第三行1列
动态初始化的特点:
- 可以灵活控制内存分配
- 适合事先不知道具体元素值的情况
- 可以创建不规则数组(每行列数不同)
8.2 二维数组的访问和遍历
元素访问
通过行索引和列索引访问元素:
int[][] matrix = {{1,2,3}, {4,5,6}};
int value = matrix[1][2]; // 获取第2行第3列的元素(值为6)
matrix[0][1] = 10; // 修改第1行第2列的元素值
遍历方法
-
标准for循环:
int[][] scores = {{85, 90}, {78, 89, 92}, {88}}; for (int i = 0; i < scores.length; i++) { // 遍历行 for (int j = 0; j < scores[i].length; j++) { // 遍历列 System.out.print(scores[i][j] + "\t"); } System.out.println(); // 换行 }
-
增强for循环(推荐):
for (int[] row : scores) { // 获取每一行 for (int score : row) { // 获取行中的每个元素 System.out.print(score + "\t"); } System.out.println(); }
-
使用Arrays工具类:
System.out.println(Arrays.deepToString(scores)); // 输出:[[85, 90], [78, 89, 92], [88]]
应用场景
二维数组常用于:
- 表格数据处理(如Excel表格)
- 矩阵运算
- 棋盘类游戏(如象棋、五子棋)
- 图像处理(像素矩阵)
- 学生成绩管理系统(行表示学生,列表示科目)
九、数组的注意事项
-
数组索引越界(ArrayIndexOutOfBoundsException): 数组的索引是从0开始计数的,如果尝试访问一个不存在的索引位置,就会发生数组越界异常。例如:
int[] numbers = {1, 2, 3}; System.out.println(numbers[3]); // 会抛出ArrayIndexOutOfBoundsException
预防措施:
- 在访问数组元素前,使用if语句检查索引是否有效
- 在循环中使用数组的length属性作为边界条件
- 对于多维数组,要分别检查每一维的索引
-
空指针异常(NullPointerException): 当数组引用未被初始化时就尝试访问其属性或元素,会导致空指针异常。常见场景包括:
- 声明数组但未初始化
- 数组被显式赋值为null后又尝试访问
int[] data = null; System.out.println(data.length); // 抛出NullPointerException
解决方法:
- 使用new关键字或数组字面量初始化数组
- 在使用数组前进行null检查
-
数组长度固定特性: Java数组的长度在创建时就已确定,无法动态改变。如果需要动态大小的集合,可以考虑:
- ArrayList:自动扩容的集合类
- System.arraycopy():手动创建新数组并复制元素
- Arrays.copyOf():更简洁的数组复制方法 示例:
// 原始数组 int[] oldArray = new int[5]; // 扩容为10的新数组 int[] newArray = Arrays.copyOf(oldArray, 10);
-
数组的引用特性: 数组是引用类型,赋值操作实际上是复制引用而非创建新数组。这种特性可能导致以下情况:
- 修改副本会影响原始数组
- 比较数组时使用"=="比较的是引用而非内容
int[] original = {1, 2, 3}; int[] copy = original; // 只是引用复制 copy[0] = 100; // 修改会影响original数组
如果需要真正的数组复制,应该使用Arrays.copyOf()或System.arraycopy()方法。
-
数组的默认值: 数组元素会根据类型自动初始化:
- 数值类型:0或0.0
- boolean:false
- 引用类型:null 示例:
double[] temps = new double[3]; System.out.println(temps[1]); // 输出0.0
注意:局部变量数组不会自动初始化,必须先明确赋值。
-
Arrays工具类的使用: java.util.Arrays提供了丰富的数组操作方法:
- 排序:Arrays.sort(arr)
- 二分查找:Arrays.binarySearch(arr, key)(要求数组已排序)
- 比较:Arrays.equals(arr1, arr2)(比较内容而非引用)
- 填充:Arrays.fill(arr, value)
- 转换为字符串:Arrays.toString(arr) 示例:
int[] scores = {85, 92, 78}; Arrays.sort(scores); // 变为[78, 85, 92] int index = Arrays.binarySearch(scores, 85); // 返回1 System.out.println(Arrays.toString(scores));