如何在Java中处理unsigned short / ints / longs

时间:2018-02-16 21:07:53

标签: java groovy

我正在读取一种文件格式,指定某些类型是无符号整数和短整数。当我读取值时,我将它们作为字节数组。我把它们变成短裤/短片/长片的最佳途径是这样的:

ByteBuffer wrapped = ByteBuffer.wrap(byteArray);
int x = wrapped.getInt();

对于无符号整数,它看起来很容易溢出。有没有更好的方法来处理这种情况?

更新:我应该提到我使用的是Groovy,所以我绝对不在乎是否必须使用BigInteger或类似的东西。我只想保持最大值的安全性。

3 个答案:

答案 0 :(得分:5)

32位值(有符号或无符号)始终可以无损存储在int *中。这意味着从数据安全的角度来看,您永远不必担心将无符号值放在有符号的类型中。

byte中的8位值,short中的16位值和long中的64位值也是如此。

一旦您将未签名的值读入相应的签名类型,就可以将它们提升为更大类型的签名值,以便更轻松地使用预期值:

由于没有大于long的原始类型,您可以通过BigInteger,或使用Long上的便捷方法进行无符号操作:

*这要归功于JVM需要integer types to be two's complement

答案 1 :(得分:1)

要保持unsigned int / short / byte,需要使用下一个“更大”类型,即long / int / short。如果您已经保留了可能溢出的签名类型的值,则可以通过执行以下操作来完成转换:

int unsignedVal = byteVal & 0xff

如果您只是投射它们,将会看到负位,您仍然会得到负值。

如果你必须处理unsigned longs,你需要“切换”到java.math.BigInteger。

答案 2 :(得分:1)

无符号原语是Java中的一个难题。

没有干净的方式处理它们,除了使用更多位的更大类型,并注意避免在施法时自动符号扩展。

在您的情况下,您可以执行以下操作:

ByteBuffer wrapped = ByteBuffer.wrap(byteArray);
int signedInt = wrapped.getInt();
long unsigned = signedInt & 0xffffffffL;

我经常在某个地方的实用程序类中编写所需的转换,因为它们很容易出错。如果你复制&粘贴到任何地方的一个班轮转换,最终一个将是错误的。

请注意,如果您需要无符号长整数,则唯一较大的类型为BigInteger

如果您需要的不仅仅是简单的转换,我建议使用Guava,因为它有一些很好的类来处理无符号类型。请参阅文档here