当我这样做的时候
Long.parseUnsignedLong("FBD626CC4961A4FC", 16)
我得到-300009666327239428
这似乎是错误的,因为根据这个答案https://stackoverflow.com/a/2550367/1754020, unsigned long的含义是范围总是正的。
要从这个HEX值中获得正确的数字,我执行
BigInteger value = new BigInteger("FBD626CC4961A4FC", 16);
当我打印value时,它打印正确的值。但如果我用value.longValue()
再次得到相同的-300009666327239428
,这是数字太大和溢出吗?
Java 8(在某种程度上)支持无符号长长度,但是,您不能直接打印它们。这样做会得到您所看到的结果。
如果你有一个unsigned long
Long number = Long.parseUnsignedLong("FBD626CC4961A4FC", 16);
可以使用
函数获得正确的字符串表示形式String numberToPrint = Long.toUnsignedString(number);
如果你现在打印numberToPrint
,你得到
18146734407382312188
更确切地说,你的数字仍然是一个常规的符号 long
,这就是为什么它显示溢出,如果直接打印。但是,有一些新的静态函数会将该值视为无符号值,例如Long.toUnsignedString(long x)
或Long.compareUnsigned(long x, long y)
。
十六进制数"FBD626CC4961A4FC"
转换成十进制后正好是18146734407382312188
。这个数字确实大于long
的最大值,定义为Long.MAX_VALUE
,它等于263-1,或者9223372036854775807
:
System.out.println(new BigInteger("FBD626CC4961A4FC", 16)); // 18146734407382312188
System.out.println(Long.MAX_VALUE); // 9223372036854775807
因此,得到一个负数是正常的。
没有异常,因为这正是在Java 8中添加的那些新的*Unsigned*
方法的目的,提供处理无符号长(如compareUnsigned
或divideUnsigned
)的能力。由于Java中的long
类型仍然是无符号的,因此这些方法通过将负值理解为大于MAX_VALUE
的值来工作:它模拟了一个无符号的long。parseUnsignedLong
说:
unsigned integer将通常与负数相关的值映射为大于
MAX_VALUE
的正数。
如果你输出的long
是parseUnsignedLong
的结果,并且它是负的,这意味着该值大于语言定义的最大长度值,但是以unsigned long作为参数的方法将正确地解释这些值,就好像它们大于最大值一样。因此,如果您将该数字传递给toUnsignedString
,而不是直接打印它,您将得到正确的输出,如另一个答案所示。并非所有这些方法都是Java 8的新方法,例如toHexString
也将给定的long
解释为16进制的unsigned long,并且打印Long.toHexString(Long.parseUnsignedLong("FBD626CC4961A4FC", 16))
将返回正确的十六进制字符串。
parseUnsignedLong
将抛出异常,只有当值不能表示为unsigned long类型,即根本不是数字,或者大于264-1(而不是263-1,这是有符号long类型的最大值)。
是的,当您试图打印它时,它会溢出,因为它被转换为Java long
类型。为了理解为什么,我们取dec值的log2。
首先,原始值是18146734407382312188
。它的log2是~63.9763437545
第二,查看文档:在java中,long类型表示值为-2^63,最大值为2^63-1。
所以,你的值明显大于2^63-1,因此它溢出:
-2^63 + (18146734407382312188 - 2^63 + 1) = -300009666327239428
但是正如@Keiwan出色地提到的,您仍然可以使用Long.toUnsignedString(number);
内部无符号数和有符号数以相同的方式表示,即在long的情况下为8字节。区别只是"符号"位的解释方式,即如果你在C/c++程序中做同样的事情,并将你的值存储到uint64_t
中,然后将其转换/映射到指定的int64_t
中,你应该得到相同的结果。
由于8字节或64位可以容纳的最大值是2^64-1,这是此类数字的硬约束。此外,Java不直接支持无符号数,因此在long
中存储unsigned long的唯一方法是允许一个高于有符号Long.MAX_VALUE
的值。事实上,Java不知道你正在读取的字符串/十六进制码是表示有符号的还是无符号的,所以由你来提供这种解释,要么转换回字符串,要么使用更大的数据类型,如BigInteger
。