方法定义

Long.compareUnsigned()java.lang.Long 类提供的静态方法,用于对两个 long 值进行无符号比较

方法签名

public static int compareUnsigned(long x, long y)
  • 参数
    • x:第一个要比较的 long
    • y:第二个要比较的 long
  • 返回值
    • 如果 x == y,返回 0
    • 如果 x < y(无符号),返回 -1
    • 如果 x > y(无符号),返回 1
  • 异常:无

功能说明

⚠️ 核心问题:Java 原生 long 是有符号的

在 Java 中,long 类型是有符号的 64 位整数,范围是:

  • 有符号:-9,223,372,036,854,775,8089,223,372,036,854,775,807

但有时我们需要将其视为无符号 64 位整数,范围是:

  • 无符号:018,446,744,073,709,551,615

compareUnsigned 的作用

将两个 long当作无符号整数进行比较,即忽略符号位(最高位),按纯数值大小比较。


示例代码

1. 基本使用(正数之间)

System.out.println(Long.compareUnsigned(5L, 10L));     // -1 (5 < 10)
System.out.println(Long.compareUnsigned(10L, 5L));     // 1  (10 > 5)
System.out.println(Long.compareUnsigned(10L, 10L));    // 0  (10 == 10)

2. 关键场景:负数 vs 正数(有符号 vs 无符号)

// 在有符号比较中:-1 < 1
System.out.println(Long.compare(-1L, 1L));           // -1

// 但在无符号比较中:-1 对应的二进制是全 1,代表最大值
System.out.println(Long.compareUnsigned(-1L, 1L));   // 1
// 解释:无符号下 -1 等于 18,446,744,073,709,551,615,远大于 1

3. 大数比较(模拟无符号行为)

// 模拟两个“大”无符号 long 值
long a = 0x8000000000000000L; // 有符号为负数,无符号为 2^63
long b = 0x7FFFFFFFFFFFFFFFL; // 有符号最大值,无符号为 2^63 - 1

System.out.println("有符号比较: " + Long.compare(a, b));         // 1 (a > b)
System.out.println("无符号比较: " + Long.compareUnsigned(a, b)); // 1 (a > b)

// 但注意:a 在有符号中是负数,b 是正数,但无符号下 a 更大

4. 与 Integer.compareUnsigned 类比

// Integer 版本同理
System.out.println(Integer.compareUnsigned(-1, 1)); // 1 (无符号下 -1 > 1)

使用技巧

✅ 技巧1:排序无符号 long 值

long[] values = {100L, -1L, 50L, 0L};

// 使用 compareUnsigned 进行无符号排序
Arrays.sort(values, Long::compareUnsigned);

// 输出:0, 50, 100, -1(因为 -1 无符号最大)
System.out.println(Arrays.toString(values));

✅ 技巧2:在 Comparator 中使用

List<Long> list = Arrays.asList(100L, -1L, 50L);

list.sort(Comparator.comparingLong(Long::longValue)
                 .thenComparing(Comparator.naturalOrder())); // 不适用

// 正确:无符号排序
list.sort(Comparator.comparingLong((Long x) -> x)
                 .thenComparing(Comparator.comparingLong(Long::longValue, Long::compareUnsigned)));
// 或更简洁:
list.sort((a, b) -> Long.compareUnsigned(a, b));

✅ 技巧3:判断无符号范围

// 判断一个 long 是否在无符号 [min, max] 范围内
public static boolean inUnsignedRange(long value, long min, long max) {
    return Long.compareUnsigned(value, min) >= 0 &&
           Long.compareUnsigned(value, max) <= 0;
}

常见错误

❌ 错误1:误用有符号比较处理无符号数据

// 错误:以为 -1 小于 1(有符号思维)
if (-1L < 1L) {
    // 正确,但不符合无符号语义
}

// 但在无符号上下文中,-1 实际上是最大值
if (Long.compareUnsigned(-1L, 1L) > 0) {
    // 正确:无符号下 -1 > 1
}

❌ 错误2:混淆 compareUnsignedcompareTo

Long a = 100L;
Long b = 200L;

// Long.compareTo 是有符号比较
int cmp1 = a.compareTo(b); // -1

// Long.compareUnsigned 是静态方法,用于无符号
int cmp2 = Long.compareUnsigned(a, b); // -1(此例结果相同)

// 但对负数不同
int cmp3 = a.compareTo(-1L);           // 1(有符号:100 > -1)
int cmp4 = Long.compareUnsigned(a, -1L); // -1(无符号:100 < 最大值)

❌ 错误3:认为 compareUnsigned 改变值本身

long x = -1L;
int result = Long.compareUnsigned(x, 1L); // 返回 1
// x 仍然是 -1L,方法不修改原值

注意事项

  1. 无符号语义:方法将 long 的 64 位全部视为数值位,最高位不再表示符号。
  2. 返回值规范:总是返回 -101,符合 Comparator 接口约定。
  3. 性能优秀:JVM 内部优化,性能接近原生比较。
  4. 线程安全:静态方法,无状态,线程安全。
  5. 与包装类无关:操作的是 long 值,与 Long 对象是否为 null 无关。

最佳实践与性能优化

场景 推荐做法
无符号比较 Long.compareUnsigned(a, b)
数组排序 Arrays.sort(long[], Long::compareUnsigned)
List 排序 list.sort(Comparator.comparingLong(...).thenComparing(Long::compareUnsigned))
范围判断 封装为工具方法使用 compareUnsigned

🔧 性能建议

  • 该方法性能极高,通常被 JVM 内联。
  • 在需要处理大整数(如哈希值、ID、时间戳)时,优先使用无符号比较避免溢出问题。

底层原理简析

compareUnsigned 的实现基于位运算技巧:

// 伪代码实现
public static int compareUnsigned(long x, long y) {
    // 通过异或判断符号是否相同
    return (x < y) ^ ((x ^ y) >> 63) ? -1 : (x == y ? 0 : 1);
    // 更清晰版本:
    return Long.compare(x + Long.MIN_VALUE, y + Long.MIN_VALUE);
    // 加上 Long.MIN_VALUE 相当于“偏移”,使无符号最小值 0 映射到有符号最小值
}

实际 JVM 使用更高效的位操作。


总结

项目 说明
核心功能 对两个 long 值进行无符号比较
关键价值 解决 Java 缺少原生无符号类型的问题
典型用途 处理哈希码、大 ID、时间戳、网络协议数据等
优点 语义清晰、性能高、线程安全
缺点 需要开发者明确区分有符号/无符号场景
性能 ⭐⭐⭐⭐⭐ 极高,推荐优先使用

💡 一句话掌握
当你需要把 long 当作无符号 64 位整数比较时,使用 Long.compareUnsigned(a, b)
它能正确处理负数(如 -1L)在无符号下是最大值的语义,
是处理大整数比较的标准工具