在处理协议报文、文件魔数、哈希值或者内存地址时,经常需要把一个 long 类型的数值转成十六进制字符串。Java 提供的 Long.toHexString() 正是干这件事的,但不少人对它的返回结果感到困惑:比如传入 -1,返回的却不是 -1,而是 ffffffffffffffff。要正确使用这个方法,必须先理解它把参数当作无符号数处理这一核心规则。

Long.toHexString() 的基本用法与格式规则
Long.toHexString() 是 java.lang.Long 类中的静态方法,方法签名为 public static String toHexString(long i)。它接收一个 long 类型的参数,将其视为无符号的 64 位整数,然后以十六进制形式返回小写的字符串表示。整个过程不涉及任何符号判断,也不会在结果前面加 0x 前缀。
看一个最简单的例子:
long value = 255; String hex = Long.toHexString(value); System.out.println(hex); // 输出: ff long bigValue = 0x1234ABCDL; System.out.println(Long.toHexString(bigValue)); // 输出: 1234abcd
注意两点:第一,输出永远是纯数字加小写字母 a 到 f,不会出现大写;第二,方法会省略高位的零。比如数值 1 转出来是 1 而不是 0000000000000001。如果对字符串长度有要求,需要自己补零,这一点后面会详细讲。
另外这个方法在底层是通过无符号移位运算实现的,大致思路是不断右移 4 位取出低 4 位,映射到对应的十六进制字符,性能开销很小,日常调用完全不需要担心效率问题。
负数转换为什么得到一长串字母 f
这是最容易踩坑的地方。Long.toHexString() 把参数当作无符号数看待,而 long 是 64 位补码表示。当传入 -1 时,它在内存中的补码形式是 64 个二进制 1,也就是 16 个十六进制的 f,所以输出是 ffffffffffffffff。
long a = -1; long b = -255; System.out.println(Long.toHexString(a)); // ffffffffffffffff System.out.println(Long.toHexString(b)); // ffffffffffffff01
可以看到,-255 转出来是 ffffffffffffff01,这与按位补码的规则完全一致。换句话说,这个方法得到的结果等价于把参数加上 2 的 64 次方之后再转换,只是它内部直接按位处理,效率更高。
反过来,如果想从这样的无符号十六进制字符串还原出 long 值,不能直接用 Long.parseLong(),因为 ffffffffffffffff 超出了有符号 long 的上限,会抛出 NumberFormatException。正确的做法是使用 Long.parseUnsignedLong(hex, 16),它同样按无符号语义解析,正好与 toHexString 形成一对互逆操作:
String hex = "ffffffffffffff01"; long restored = Long.parseUnsignedLong(hex, 16); System.out.println(restored); // -255
这种双向转换在解析网络协议字段、校验文件哈希时非常实用,务必记住配对使用。
与 toString、toBinaryString、toOctalString 的对比
Long 类提供了一组进制转换方法,理解它们的差异有助于选对工具。toString(long) 转十进制且带符号,负数会带负号;toHexString、toOctalString、toBinaryString 则全部按无符号处理,分别对应十六进制、八进制和二进制。
举个例子,对同一个值 -255 分别调用这些方法:
long v = -255; System.out.println(Long.toString(v)); // -255 System.out.println(Long.toHexString(v)); // ffffffffffffff01 System.out.println(Long.toOctalString(v)); // 1777777777777777777401 System.out.println(Long.toBinaryString(v)); // 64个1和01组成的串
还有一个容易混淆的方法是带两个参数的 toString(long i, int radix),它虽然也支持传 16 进制,但对负数的处理与 toString 一致,会在结果前加负号,例如 Long.toString(-255, 16) 的结果是 -ff。这与 toHexString 的无符号语义完全不同,解析时报文的场景几乎都应该用后者。
补零、大写与格式化的常见需求
实际开发中经常要求十六进制字符串固定 16 位长度,比如显示内存地址或消息摘要。toHexString 会省略高位零,这时可以借助 String.format 来补齐:
long value = 0xABL;
// 补齐到16位小写
String lower = String.format("%016x", value);
// 补齐到16位大写
String upper = String.format("%016X", value);
System.out.println(lower); // 00000000000000ab
System.out.println(upper); // 00000000000000AB另一种做法是先转换再用 String.padStart 类似思路手动补齐,不过 Java 里更常见的是直接用 format,代码更简洁。如果只是想把已有的小写结果转大写,调用 hex.toUpperCase() 即可,或者反过来用 toLowerCase()。
在字节序敏感的场景,比如把一个 long 拆成 8 个字节的十六进制表示时,还需要注意大小端问题。可以配合 ByteBuffer 处理:
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
long value = 0x123456789ABCDEFFL;
ByteBuffer buffer = ByteBuffer.allocate(8);
buffer.order(ByteOrder.LITTLE_ENDIAN);
buffer.putLong(value);
byte[] bytes = buffer.array();
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
System.out.println(sb); // ffcdab7856341200 风格的小端字节序这里对每个字节用 %02x 补齐两位,是为了避免单个字节小于 16 时只输出一个字符导致字符串错位,这是字节级十六进制转换里非常经典的坑。
总结
Long.toHexString() 的核心要点有三个:一是按无符号语义处理参数,负数得到的是补码位模式的十六进制;二是输出小写且省略高位零,需要定长时用 String.format("%016x", v) 补齐;三是还原时必须配对使用 Long.parseUnsignedLong(hex, 16),否则超范围字符串会解析失败。掌握这些规则后,无论是协议解析、哈希展示还是调试打印,长整型与十六进制之间的转换都能轻松应对。
Long.toHexString十六进制转换Java长整型修改时间:2026-09-16 00:21:36