Arrays.binarySearch不是黑箱,小数组(如JDK8中长度<21)走线性扫描以优化缓存性能,大数组才启用防溢出的二分查找;它不校验排序,乱序时结果不可预测;返回值≥0为索引,<0则为-(插入点+1),需按位取反还原插入位置。

Arrays.binarySearch 不是“一搜就灵”的黑箱,它的性能优势只在特定条件下兑现,逻辑细节也常被误读。用得对,它能把查找从 O(n) 压到 O(log n);用错了,可能比遍历还慢,甚至返回看似合理却完全错误的结果。
小数组走线性扫描,不是 bug 是优化
别以为 binarySearch 一定执行二分——JDK 8 中,长度小于 21 的数组会直接 for 循环遍历。这不是偷懒,而是现代 CPU 缓存友好性的实际选择:短距离顺序访问比反复计算中点、分支跳转更快。
- 长度为 15 的 int[] 查找一个数,底层是简单循环,不是 mid = (low + high) / 2
- 这个阈值不公开,不同 JDK 版本可能调整,你不需也不该硬编码依赖它
- 所以对几十个元素的配置数组或枚举缓存,用 binarySearch 没问题,但别期待“二分加速”,它本来就没启动二分
大数组才真正二分,但防溢出和边界很较真
一旦数组够长,binarySearch 才启用标准二分流程,但实现比教科书更严谨:
- 中点计算用 low + (high - low) / 2,而非 (low + high) / 2,避免索引超 int 范围(比如数组长度接近 2³¹)
- 循环条件是 low <= high,确保单元素区间也能检查,不会漏掉 arr[0] 或 arr[n-1]
- 查不到时返回 -(insertion point) - 1,不是简单 -1 —— 这个负数自带位置信息,按位取反(~result)就能还原插入索引
不校验排序,错得静默且不可预测
这是最易踩坑的一点:binarySearch 完全不检查你传的数组是否真有序。它默认你已排好,直接开搜。
- 乱序数组可能返回正数,但那个索引对应的值根本不是你要找的
- 也可能返回负数,但 -(insertion point) - 1 的语义已失效,因为“插入点”在无序前提下毫无意义
- 它不会抛异常、不打日志、不警告——错误结果由你代码承担,线上排查时往往绕一大圈才回到排序这步
返回值不是布尔,而是带语义的整数
理解返回值才能用好它:
- ≥ 0:找到,值就是索引,但不保证是最左或最右的重复位置
- < 0:未找到,值 = -(应插入位置) - 1。例如 [1,3,5,7] 查 4,返回 -3 → 插入点是 2(即放在索引 2 处),~(-3) == 2
- 空数组查任意值,固定返回 -1(因为插入点恒为 0,-(0)-1 = -1)
对象数组和原始类型不能混用
int[] 和 Integer[] 对应不同重载方法,Java 不自动转换:
- 传 int[] 却调用
binarySearch(Object[], Object)→ 编译失败 - 传 Integer[] 却调用
binarySearch(int[], int)→ 编译失败 - Integer[] 版本涉及装箱/拆箱,百万级数据下比 int[] 慢 3–5 倍,性能敏感场景务必选对重载


















