Long.rotateLeft()
和 Long.rotateRight()
是 java.lang.Long
类中提供的位旋转(Bit Rotation)操作方法,用于对 64 位 long
值的二进制位进行循环左移或循环右移。它们在加密算法、哈希函数、随机数生成等底层算法中非常有用。
📚 一、方法定义
1. Long.rotateLeft(long i, int distance)
public static long rotateLeft(long i, int distance)
- 功能:将
long
值i
的二进制位向左循环移动distance
位。 - 返回值:旋转后的
long
值。
2. Long.rotateRight(long i, int distance)
public static long rotateRight(long i, int distance)
- 功能:将
long
值i
的二进制位向右循环移动distance
位。 - 返回值:旋转后的
long
值。
⚠️ 注意:这两个方法返回的是
long
基本类型,不是Long
对象。
🔍 二、核心概念:什么是“位旋转”?
与普通的“逻辑/算术移位”不同,位旋转(也称循环移位)的特点是:
- 被移出的一端的位会从另一端重新插入,不会丢失。
- 所有 64 个位整体像一个“环”一样循环移动。
🔄 对比:移位 vs 旋转
操作 | 示例(8位简化) |
---|---|
<< 2 (左移) |
10110100 << 2 → 11010000 (左边丢弃,右边补0) |
rotateLeft(2) |
10110100 → 11010010 (左边移出的 10 从右边补回) |
💡 三、工作原理与计算方式
✅ 1. rotateLeft(i, distance)
等价于:
(i << distance) | (i >>> (-distance & 63))
或更直观理解:
- 左移
distance
位 - 将左移时“溢出”的高位,通过无符号右移补到低位
✅ 2. rotateRight(i, distance)
等价于:
(i >>> distance) | (i << (-distance & 63))
- 右移
distance
位 - 将右移时“溢出”的低位,通过左移补到高位
🔢 为什么是
& 63
?
因为long
是 64 位,distance & 63
相当于distance % 64
,确保位移量在 0~63 范围内,避免无效移位。
🧪 四、示例代码
示例 1:基本使用
public class LongRotateExample {
public static void main(String[] args) {
long value = 0x123456789ABCDEF0L; // 64位十六进制数
System.out.printf("原始值: %16s%n", Long.toBinaryString(value));
// 循环左移 4 位
long left = Long.rotateLeft(value, 4);
System.out.printf("左旋 4: %16s%n", Long.toBinaryString(left));
// 循环右移 4 位
long right = Long.rotateRight(value, 4);
System.out.printf("右旋 4: %16s%n", Long.toBinaryString(right));
// 验证:左旋4 + 右旋4 应该回到原值
long roundTrip = Long.rotateRight(Long.rotateLeft(value, 4), 4);
System.out.println("往返验证: " + (value == roundTrip)); // true
}
}
示例 2:小数值演示(便于观察)
// 以 8 位为例(实际是 64 位)
long x = 0b11001010L; // 二进制表示
System.out.println("原始: " + Long.toBinaryString(x)); // 11001010
long left1 = Long.rotateLeft(x, 2);
System.out.println("左旋2: " + Long.toBinaryString(left1));
// 00101011 → 左边的 '11' 移到右边
long right1 = Long.rotateRight(x, 2);
System.out.println("右旋2: " + Long.toBinaryString(right1));
// 10110010 → 右边的 '10' 移到左边
示例 3:位移量大于 64 的情况
long val = 0b1010L;
// rotateLeft(66) 等价于 rotateLeft(66 % 64 = 2)
long result = Long.rotateLeft(val, 66);
// 实际左移 2 位
🛠️ 五、使用技巧
技巧 | 说明 |
---|---|
✅ 用于实现哈希函数 | 如 MurmurHash、xxHash 中广泛使用位旋转 |
✅ 提高位混淆性 | 旋转比普通移位更能打乱位分布,增强随机性 |
✅ 避免信息丢失 | 与 << />> 不同,旋转不会丢失任何位 |
✅ 可组合使用 | rotateLeft(a, 13) ^ rotateLeft(a, 23) 是常见混淆操作 |
✅ 替代手动位操作 | 比手动写 (i << n) | (i >>> (64-n)) 更简洁安全 |
⚠️ 六、注意事项
位移量自动取模:
distance
会被自动对 64 取模(通过& 63
),所以rotateLeft(x, 70)
等价于rotateLeft(x, 6)
。
无符号右移
>>>
:- 内部使用
>>>
而非>>
,确保高位补 0,避免符号位影响。
- 内部使用
性能极高:
- 这些方法通常被 JVM 优化为单条 CPU 指令(如 x86 的
rol
/ror
),性能极佳。
- 这些方法通常被 JVM 优化为单条 CPU 指令(如 x86 的
不可变性:
- 原始值不变,返回新值。
❌ 七、常见错误
错误 | 正确做法 |
---|---|
误以为是普通移位 | 明确区分 << 与 rotateLeft() |
期望返回 Long 对象 |
返回的是 long 基本类型 |
忽视负数位移量 | 负的 distance 也会被处理(如 rotateLeft(x, -4) 等价于 rotateRight(x, 4) ) |
手动实现错误 | 忘记使用 >>> 或未处理 64-n 边界 |
🏆 八、最佳实践与性能优化
场景 | 推荐 |
---|---|
✅ 哈希/加密算法 | 使用 rotateLeft/Right 增强混淆 |
✅ 随机数生成 | 用于状态混淆(如 SplitMix64) |
✅ 高性能位操作 | 替代复杂位运算组合 |
❌ 普通业务逻辑 | 除非必要,避免使用(可读性较低) |
示例:模拟 SplitMix64 的部分操作
long z = seed + 0x9E3779B97F4A7C15L;
z = (z ^ (z >>> 30)) * 0xBF58476D1CE4E5B9L;
z = (z ^ (z >>> 27)) * 0x94D049BB133111EBL;
return Long.rotateLeft(z, 31); // 最终混淆
📊 九、性能对比(与手动实现)
方法 | 性能 | 可读性 | 推荐度 |
---|---|---|---|
Long.rotateLeft(x, n) |
⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ✅ 推荐 |
(x << n) | (x >>> (64-n)) |
⭐⭐⭐⭐ | ⭐⭐ | 一般 |
查表法 | ⭐⭐ | ⭐⭐⭐⭐ | 仅特殊场景 |
✅
Long.rotateLeft/Right
是 JVM 内置优化方法,性能最优。
📝 十、总结
项目 | 内容 |
---|---|
核心功能 | 对 long 值进行循环左移/右移 |
关键优势 | 无位丢失、高性能、CPU 指令级优化 |
典型应用 | 哈希函数、加密算法、随机数生成 |
注意事项 | 返回 long 而非 Long ,位移量自动取模 64 |
与移位区别 | 旋转是“环形”移动,移位是“线性”移动 |
性能 | 极高,通常编译为单条 CPU 指令 |
推荐使用 | ✅ 在需要位混淆或循环移位时首选 |
✅ 一句话掌握:
用
Long.rotateLeft(x, n)
和Long.rotateRight(x, n)
实现 64 位值的循环移位,比手动位运算更安全高效,是高性能算法的基石操作。