Long.toHexString() 不补前导零,返回小写十六进制字符串;需固定16位应使用 String.format("%016x", value),负数按补码处理,性能敏感时可用 StringBuilder 手动补零。

Long.toHexString() 会丢弃前导零,这很常见但容易被忽略
Long.toHexString() 返回的是不带前导零的十六进制字符串,比如 0L 得到 "0",1L 是 "1",而 255L 是 "ff"。它不会补足 16 位(对应 long 的 64 位、16 字节十六进制),这点和 String.format("%016x", n) 行为完全不同。
如果你需要固定长度(如调试内存地址、序列化、校验对齐),直接调用 Long.toHexString() 就不够用。
- 它只做数值转小写十六进制,不处理格式化
- 输入负数时按补码解释,结果仍是合法十六进制(如
Long.toHexString(-1L)→"ffffffffffffffff") - 返回值永远是小写字母
a–f,没有大写选项
想补零到 16 位?别手写循环,用 String.format 最稳
要得到类似 "00000000000000ff" 这样的 16 字符输出,String.format("%016x", value) 是最直接可靠的方案。
注意:这里的 %016x 含义是「至少 16 位,不足左补 0,小写十六进制」;%016X 则输出大写。
-
String.format("%016x", 255L)→"00000000000000ff" -
String.format("%016x", 0L)→"0000000000000000" -
String.format("%016x", -1L)→"ffffffffffffffff"(64 位全 1,刚好 16 字符,不补零) - 如果 value 超出 long 范围,编译器会报错,无需额外检查
性能敏感场景下,避免重复创建 Formatter 实例
String.format() 内部每次调用都会新建 Formatter 对象,高频转换(如日志埋点、网络序列化循环)可能带来 GC 压力。
这时可考虑预编译或手动填充逻辑,但前提是实测确认它是瓶颈——多数业务场景无需优化。
- 简单复用:把
new DecimalFormat("0000000000000000")这类思路套在 hex 上行不通,因为它是十进制专用 - 真正高效的做法是用
StringBuilder手动拼接:先调用Long.toHexString(),再计算缺多少位,前面append对应数量的'0' - 例如:
String hex = Long.toHexString(v); StringBuilder sb = new StringBuilder(16); for (int i = hex.length(); i 注意:负数结果长度恒为 16,可跳过补零
遇到 "NumberFormatException: For input string: 'ff'"?不是 toHexString 的锅
这个错误通常出现在你试图把 Long.toHexString() 的输出再用 Long.parseLong(s, 16) 解析回来,却忘了传进制参数,或者用了错误的进制(比如传了 10)。
- 正确还原:
Long.parseLong("ff", 16)→255L - 错误写法:
Long.parseLong("ff")默认按十进制解析,必然抛异常 - 更隐蔽的问题:
Long.parseLong("8000000000000000", 16)会溢出(超出Long.MAX_VALUE),应改用new BigInteger(s, 16).longValue()或直接接受它就是Long.MIN_VALUE
补零逻辑和负数处理是实际使用中最常翻车的地方,尤其在跨语言对接或二进制协议解析时,少一位 0 或大小写不一致都可能导致校验失败。










