Long.toBinaryString() 返回无符号二进制字符串(省略前导零),非补码表示;对负数因内存存为补码且不省略高位1,结果恰等价于补码去零后形式。

Long.toBinaryString() 方法**不会生成二进制补码表示**,它只返回该 long 值的**无符号二进制字符串形式**(即绝对值的二进制,不带符号位,也不补全位数)。
为什么不是补码?
Java 中的 Long.toBinaryString(long value) 的行为是:
- 对非负数(≥ 0),直接输出其自然二进制表示,如
toBinaryString(5)→"101"; - 对负数(如
-1),它仍按“无符号解释”处理:把long当作 64 位无符号整数看待,输出全部 64 位中**最高有效位起第一个 1 之后的二进制串**(即省略前导零); - 它**不添加符号位、不强制 64 位、不显式体现补码逻辑**——但巧合的是,由于 Java 中负数在内存里本就是以补码存储的,所以对负数调用该方法,结果恰好等于该数补码形式去掉前导零后的字符串。
例如:
Long.toBinaryString(-1) → "1111111111111111111111111111111111111111111111111111111111111111"(64 个 1)
这是因为 -1 的补码确实是 64 个 1,而该方法不省略任何位(因为最高位就是 1),所以看起来“像补码”。
但再看:Long.toBinaryString(-2) → "1111111111111111111111111111111111111111111111111111111111111110"(63 个 1 + 1 个 0),这也是 -2 的 64 位补码,没错。
但它不补全位数,也不处理符号逻辑
关键区别在于:toBinaryString() 是“懒惰输出”——它从第一个 1 开始截取,不保证长度。比如:
-
Long.toBinaryString(1)→"1"(不是"000...001") -
Long.toBinaryString(0)→"0" -
Long.toBinaryString(-1L & 0xFFFFFFFFL)(强制低 32 位)→ 可能输出 32 位字符串,但这已是手动干预。
如何获得标准 N 位补码字符串(如 64 位)?
若你明确需要固定长度(如 64 位)的补码二进制字符串,推荐用以下方式:
- 利用
String.format("%64s", Long.toBinaryString(x & 0xFFFFFFFFFFFFFFFFL)).replace(' ', '0')(注意:0xFFFFFFFFFFFFFFFFL是 64 位掩码,用于无符号扩展); - 更安全简洁的方式:
String.format("%64s", Long.toBinaryString(x)).replace(' ', '0')—— 但此法对正数有效,对负数因原始结果已满 64 位,实际也成立; - 最可靠通用做法(兼容所有情况):
String.format("%64s", Long.toBinaryString(x 不够准确;应改用:<br><code>String.format("%64s", Long.toBinaryString(x & 0xFFFFFFFFFFFFFFFFL)).replace(' ', '0')
总结:别误解它的语义
Long.toBinaryString() 返回的是数值的**无符号二进制表示(省略前导零)**,不是“补码转换函数”。只是因为 Java 负数内存布局即为补码,且该方法对负数会输出全部 64 位(无省略),结果才等价于补码字符串(去掉前导零后)。如需固定宽度或教学演示补码过程,务必自行补零或使用位运算+格式化控制。










