【问题标题】:How to handle unsigned shorts/ints/longs in Java如何在 Java 中处理 unsigned short/int/long
【发布时间】:2018-02-16 21:07:53
【问题描述】:

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

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

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

更新:我应该提到我正在使用 Groovy,所以我绝对不在乎是否必须使用 BigInteger 或类似的东西。我只希望在保持价值不变的情况下获得最大的安全性。

【问题讨论】:

  • 取决于你想用它们做什么。如果要将它们用作实际数值,则必须读取它们,将它们提升(即分配)到下一个更大的大小,然后屏蔽可能扩展的符号位。

标签: java groovy


【解决方案1】:

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

bytes 中的 8 位值、shorts 中的 16 位值和longs 中的 64 位值也是如此。

将无符号值读入相应的有符号类型后,您可以将它们提升为更大类型的有符号值,以便更轻松地使用预期值:

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


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

【讨论】:

  • 很好,我不知道这些是在 Java 8 中添加的。
【解决方案2】:

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

int unsignedVal = byteVal & 0xff

如果你只是施放它们,负位将被视为,你仍然会得到负值。

如果您必须处理无符号长整数,则需要“切换”到 java.math.BigInteger。

【讨论】:

    【解决方案3】:

    无符号原语在 Java 中是一种痛苦。

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

    在你的情况下,你可以这样做:

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

    我通常在某个地方的实用程序类中编写所需的转换,因为它们很容易出错。如果您在任何地方复制并粘贴该一个线性转换,最终会出现错误。

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-13
      • 1970-01-01
      • 1970-01-01
      • 2016-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多