方法定义
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,808
到9,223,372,036,854,775,807
但有时我们需要将其视为无符号 64 位整数,范围是:
- 无符号:
0
到18,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:混淆 compareUnsigned
与 compareTo
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,方法不修改原值
注意事项
- 无符号语义:方法将
long
的 64 位全部视为数值位,最高位不再表示符号。 - 返回值规范:总是返回
-1
、0
或1
,符合Comparator
接口约定。 - 性能优秀:JVM 内部优化,性能接近原生比较。
- 线程安全:静态方法,无状态,线程安全。
- 与包装类无关:操作的是
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
)在无符号下是最大值的语义,
是处理大整数比较的标准工具。