Java中64位Long位操作问题求助(不使用Bitset)
解决Java中Long类型位操作的符号位问题
你猜的完全没错!这个异常就是Java中有符号长整型的符号位扩展导致的。咱们来一步步拆解问题,再给出高效的解决方案:
问题根源
Java里的long是64位有符号整数,但你代码里的1 << index是用32位有符号的int来计算的——因为字面量1默认是int类型。当你操作第31位时,1 << 31会让32位int的符号位被置1,变成负数;当这个值自动转成long时,Java会做符号扩展,把高位的32位全部补成1,这就导致你后续的位操作结果带上了一堆多余的1,最终打印出来就异常了。
高效修复方案
只需要把移位操作的基准值改成long类型的1L,确保所有位操作都在64位无符号语境下进行,同时优化打印方法避免补码干扰:
1. 修正位操作方法
// 翻转指定位置的位 static final long toggle_bit(long number, int index) { return number ^ (1L << index); } // 置位指定位置 static final long set_bit(long number, int index) { return number | (1L << index); } // 复位指定位置 static final long unset_bit(long number, int index) { return number & ~(1L << index); }
这里把1换成1L后,移位操作就会在64位long的范围内执行,不会触发32位int的符号位问题,不管操作0~63位中的哪一位都能正常工作。
2. 优化二进制打印方法
原来的Long.toBinaryString()会输出负数的补码形式,导致前面全是1。改用Long.toUnsignedString()可以强制按无符号64位格式输出,再补前导零即可:
static final void print_bits(long number) { String binary = Long.toUnsignedString(number, 2); // 生成64个0的字符串,用来补前导零 String padding = "0".repeat(64); // 拼接成完整的64位二进制字符串 String fullBinary = padding.substring(binary.length()) + binary; System.out.println(fullBinary); }
额外建议
可以给位操作方法加上参数校验,避免传入超出0~63范围的index(Java的移位操作会对位数取模64,比如index=64等价于0位,可能不符合你的预期):
if (index < 0 || index >= 64) { throw new IllegalArgumentException("Index must be between 0 and 63"); }
现在再调用set_bit(0L, 31),打印出来的就是正常的64位二进制字符串啦!
内容的提问来源于stack exchange,提问作者Finn Eggers
相关产品推荐
相关产品推荐

