一、方法定义
1. Long.numberOfLeadingZeros(long i)
public static int numberOfLeadingZeros(long i)
- 功能:返回
long
值的二进制补码表示中,最高位1之前的零的个数。
- 参数:
i
- 要计算的 long 值
- 返回值:前导零的个数(0 到 64)
- 异常:无
2. Long.numberOfTrailingZeros(long i)
public static int numberOfTrailingZeros(long i)
- 功能:返回
long
值的二进制补码表示中,最低位1之后的零的个数。
- 参数:
i
- 要计算的 long 值
- 返回值:尾随零的个数(0 到 64)
- 异常:无
⚠️ 注意:两个方法都基于 64位二进制补码表示 进行计算。
二、功能说明
方法 |
功能描述 |
numberOfLeadingZeros |
计算从最高位(第63位)开始,连续的 0 的个数,直到遇到第一个 1 为止。 |
numberOfTrailingZeros |
计算从最低位(第0位)开始,连续的 0 的个数,直到遇到第一个 1 为止。 |
特殊情况:
i == 0
时:
numberOfLeadingZeros(0)
→ 64
numberOfTrailingZeros(0)
→ 64
i < 0
(负数):
- 所有负数的最高位是
1
,所以 numberOfLeadingZeros
返回 0
i
是奇数:
- 最低位是
1
,所以 numberOfTrailingZeros
返回 0
三、示例代码
1. 基本用法示例
public class NumberOfZerosExample {
public static void main(String[] args) {
// 正数示例
System.out.println(Long.numberOfLeadingZeros(1L)); // 63 (二进制: ...0001)
System.out.println(Long.numberOfLeadingZeros(8L)); // 60 (二进制: ...1000)
System.out.println(Long.numberOfLeadingZeros(255L)); // 56 (二进制: ...11111111)
System.out.println(Long.numberOfTrailingZeros(8L)); // 3 (二进制: ...1000)
System.out.println(Long.numberOfTrailingZeros(12L)); // 2 (二进制: ...1100)
System.out.println(Long.numberOfTrailingZeros(7L)); // 0 (二进制: ...0111, 奇数)
// 零
System.out.println(Long.numberOfLeadingZeros(0L)); // 64
System.out.println(Long.numberOfTrailingZeros(0L)); // 64
// 负数
System.out.println(Long.numberOfLeadingZeros(-1L)); // 0 (全为1: 111...111)
System.out.println(Long.numberOfLeadingZeros(-8L)); // 0
}
}
2. 二进制可视化辅助理解
public static void printBinaryAndZeros(long value) {
String binary = Long.toBinaryString(value);
// 补全64位便于观察
binary = String.format("%64s", binary).replace(' ', '0');
int leading = Long.numberOfLeadingZeros(value);
int trailing = Long.numberOfTrailingZeros(value);
System.out.printf("Value: %d\n", value);
System.out.printf("Binary: %s\n", binary);
System.out.printf("Leading zeros: %d\n", leading);
System.out.printf("Trailing zeros: %d\n", trailing);
System.out.println("---");
}
// 使用示例
printBinaryAndZeros(8); // Leading: 60, Trailing: 3
printBinaryAndZeros(12); // Leading: 60, Trailing: 2
printBinaryAndZeros(0); // Leading: 64, Trailing: 64
四、使用技巧
技巧 |
说明 |
✅ 判断是否为2的幂 |
(i & (i-1)) == 0 且 i > 0 ,或结合 numberOfTrailingZeros 使用 |
✅ 计算最高位位置 |
63 - numberOfLeadingZeros(i) 得到最高位1的位置(0~63) |
✅ 计算最低位位置 |
numberOfTrailingZeros(i) 直接得到最低位1的位置 |
✅ 快速除以2的幂 |
numberOfTrailingZeros 可用于优化位移操作 |
✅ 位掩码生成 |
结合使用可生成动态掩码 |
// 判断是否为2的幂(正数)
public static boolean isPowerOfTwo(long n) {
return n > 0 && (n & (n - 1)) == 0;
}
// 获取最高位的位置(从0开始)
public static int highestOneBitPosition(long n) {
return 63 - Long.numberOfLeadingZeros(n);
}
// 获取最低位的位置
public static int lowestOneBitPosition(long n) {
return Long.numberOfTrailingZeros(n);
}
五、常见错误
错误 |
原因 |
修复方式 |
❌ 误认为负数有前导零 |
负数最高位为1,前导零为0 |
理解补码表示 |
❌ 忽略 0 的特殊情况 |
0 的前后导零都是64 |
显式处理 i == 0 的情况 |
❌ 期望返回二进制字符串长度 |
它返回的是零的个数,不是位数 |
使用 64 - numberOfLeadingZeros(i) 计算有效位数(非零时) |
❌ 混淆 leading 与 trailing |
记错方向 |
leading = 开头,trailing = 结尾 |
六、注意事项
- 基于64位补码:所有计算基于
long
的64位二进制表示。
- 性能极高:这两个方法通常由 JVM 直接映射到 CPU 指令(如
CLZ
, CTZ
),性能极佳。
- 无异常抛出:任何
long
值都可安全调用。
- 0 的特殊性:
0
没有 1
,因此前后导零均为64。
- 负数前导零为0:因为符号位是
1
。
七、最佳实践
实践 |
推荐做法 |
🔹 位操作优化 |
在位运算、掩码、标志位处理中使用 |
🔹 性能敏感场景 |
替代循环计算位位置 |
🔹 结合 Long.highestOneBit() / Long.lowestOneBit() |
综合使用进行位分析 |
🔹 算法题常用 |
如求最大公约数、快速幂、位计数等 |
🔹 日志调试 |
输出二进制+前后导零信息辅助调试 |
// 实际应用:计算一个数的二进制表示长度(有效位数)
public static int bitLength(long n) {
if (n == 0) return 1;
return 64 - Long.numberOfLeadingZeros(n);
}
八、性能优化建议
场景 |
优化策略 |
⚡ 高频位分析 |
直接使用 numberOfLeadingZeros ,避免手动循环 |
⚡ 替代 Math.log(x) / Math.log(2) |
计算以2为底的对数时更高效 |
⚡ 位扫描 |
使用 numberOfTrailingZeros 实现“找下一个1”的高效算法 |
✅ 这两个方法本身就是性能优化的结果,无需手动实现。
九、与相关方法对比
方法 |
关联 |
Integer.numberOfLeadingZeros() |
功能相同,但针对 int (32位) |
Long.bitCount() |
计算二进制中 1 的个数 |
Long.highestOneBit() |
返回最高位的1,如 8 → 8 ,12 → 8 |
Long.lowestOneBit() |
返回最低位的1,如 12 → 4 |
✅ 联合使用示例:
long n = 24; // 11000
int leading = Long.numberOfLeadingZeros(n); // 59
int trailing = Long.numberOfTrailingZeros(n); // 3
int ones = Long.bitCount(n); // 2
long highBit = Long.highestOneBit(n); // 16
long lowBit = Long.lowestOneBit(n); // 8
十、总结
项目 |
内容 |
✅ 核心功能 |
分别计算 long 值二进制表示中前导零和尾随零的个数 |
✅ 关键特性 |
基于64位补码、性能极高、无异常 |
✅ 典型用途 |
位运算优化、算法实现、性能敏感计算、调试分析 |
✅ 使用要点 |
理解补码、注意 0 和负数的特殊情况 |
✅ 最佳实践 |
与位操作结合、替代循环、用于高效算法 |
✅ 避坑指南 |
0 返回64,负数前导零为0 |
💡 一句话掌握:
numberOfLeadingZeros
和 numberOfTrailingZeros
是 Java 提供的高效位分析工具,基于 CPU 指令优化,用于快速定位二进制中 1
的位置,是位运算和性能优化的利器。