一、方法定义

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)) == 0i > 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) 计算有效位数(非零时)
❌ 混淆 leadingtrailing 记错方向 leading = 开头,trailing = 结尾

六、注意事项

  1. 基于64位补码:所有计算基于 long 的64位二进制表示。
  2. 性能极高:这两个方法通常由 JVM 直接映射到 CPU 指令(如 CLZ, CTZ),性能极佳。
  3. 无异常抛出:任何 long 值都可安全调用。
  4. 0 的特殊性0 没有 1,因此前后导零均为64。
  5. 负数前导零为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,如 88128
Long.lowestOneBit() 返回最低位的1,如 124

✅ 联合使用示例:

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

💡 一句话掌握
numberOfLeadingZerosnumberOfTrailingZeros 是 Java 提供的高效位分析工具,基于 CPU 指令优化,用于快速定位二进制中 1 的位置,是位运算和性能优化的利器